/**
 * 无控件版本软电话核心类
 * Created by Lori on 2016/8/16.
 */

(function (factory) {
    'use strict';

    window.sccrossorigin = false;
    window.scpath  = "";
    window.scfileext = "";

    //console.log("softphone.core.window", window);
    //console.log("softphone.core.currentScript", document.currentScript);
    if (document.currentScript && document.currentScript != null) {
        console.log("document.currentScript.src", document.currentScript.src);
        window.scpath =  document.currentScript.src.substr(0, document.currentScript.src.lastIndexOf("/"));
        if (!window.scpath.startWith(document.location.origin)) {
            window.sccrossorigin = true;
            window.scfileext = ".js"
        }
    }
    if (!window.sccrossorigin) {
        window.scpath = $E.softphoneBasePath + "/softphone";
        window.scfileext = "";
    }
    //console.log("00: scpath, sccorssorigin, scfileext", window.scpath, window.sccrossorigin, window.scfileext);

    if (typeof define === 'function' && define.amd) {
        define([scpath + '/softphone.ini' + scfileext, scpath + "/softphone.constants" + $E.jsv + scfileext], factory);
        //define([$E.softphoneBasePath + '/softphone/softphone.ini', $E.softphoneBasePath + "/softphone/softphone.constants" + $E.jsv], factory);
    } else if (typeof exports !== 'undefined') {
        //module.exports = factory();
    } else {
        //factory();
    }

}(function (iniconfig, $CTI_CONST) {
    'use strict';

    window.$CTI_CONST = $CTI_CONST;

    var cticlient;	// = ELITEWSCTIClient;

    var m_timer = null;

    var sccrossorigin = window.sccrossorigin;
    var scpath = window.scpath;
    var scfileext = window.scfileext;

    console.log("scpath, sccorssorigin, scfileext", scpath, sccrossorigin, scfileext);

    window.sccrossorigin = undefined;
    window.scpath = undefined;
    window.scfileext = undefined;

    if (sccrossorigin) {
        //let blob = new Blob(['importScripts("' + $E.softphoneBasePath + "/softphone/webworker_timer.min.js" + '")'], {"type": "application/javascript"});
        let blob = new Blob(['importScripts("' + scpath + "/webworker_timer.min.js" + '")'], {"type": "application/javascript"});
        let bloburl = window.URL.createObjectURL(blob);
        m_timer = new Worker(bloburl);
    } else {
        m_timer = new Worker($E.softphoneBasePath + "/softphone/webworker_timer.min.js");
    }
    var m_timerCallers = {};
    m_timer.onmessage = function(event) {
        var timer = event.data.timer;
        if (event.data.eventtype === "timer") {
            if (m_timerCallers[timer.timerUUID] && m_timerCallers[timer.timerUUID].callback) {
                var newdate = new Date().valueOf();
                var gap = newdate - m_timerCallers[timer.timerUUID].time;
                m_timerCallers[timer.timerUUID].time = newdate;
                m_timerCallers[timer.timerUUID].callback(timer.count, gap, timer.time);
            }
        }
        if (event.data.eventtype === "timerStart") {
            logmsg("softphone.core.timer", event.data);
            m_timerCallers[timer.timerUUID].timerId = timer.timerId;
        }
        if (event.data.eventtype === "timerEnd") {
            logmsg("softphone.core.timer", event.data);
            delete m_timerCallers[timer.timerUUID];
        }
    };

    function getProperty(object, path) {
        if (object === undefined)
            return undefined;

        var cs = path.indexOf('.');
        if (cs == -1)
            return object[path];

        return getProperty(object[path.substring(0, cs)], path.substring(cs+1));
    };

    //$.getScript($E.softphoneBasePath + "/softphone/softphonelang." +  ($E.lang || "zh_CN") + ".js");
    $.getScript(scpath + "/softphonelang." +  ($E.lang || "zh_CN") + ".js");

    for (let x in iniconfig) {
        for (let y in iniconfig[x]) {
            iniconfig[x][y.toLowerCase()] = iniconfig[x][y];
            if (y != y.toLowerCase()) {
                delete iniconfig[x][y];
            }
        }
    }

    function logmsg()
    {
        $SC.log(arguments);
    }

    function logreceive() {
        logmsg("receive ", arguments)
    }

    function logret() {
        logmsg("return ", arguments);
    }

    function logreq() {
        logmsg("request ", arguments);
    }

    var _iniconfig = iniconfig;

    const AGSTATE = {
        AS_LOGIN: 1,
        AS_READY: 2,
        AS_NOTREADY: 3,      //3-aux, 4-acw, 9-dnd, 21-precall
        AS_BUSY: 4,          //talking
        AS_LOGOUT: 5,
        AS_RINGING: 20,
        AS_PRECALL: 21,
        AS_HOLD: 22,
        AS_DIALING: 23,
        AS_OFFHOOK: 24,
        AS_HOLDDIALING: 25,
        AS_CONFERENCE: 26,
        AS_LISTEN: 27,
        AS_INTERCEPT: 28,
        AS_LISTENED: 29,
        AS_INTERCEPTED: 30,
        AS_MULTIMEDIA: 31,
        AS_HOLDTALKING: 32
    };

    /*
    var AGENTREPORTTYPE =
        {
            AGREPORT_LOGIN: 1,      //1,0
            AGREPORT_READY: 2,      //2,2
            AGREPORT_AUX: 3,        //3,3
            AGREPORT_ACW: 4,        //3,4
            AGREPORT_BUSY: 5,       //4,0
            AGREPORT_LOGOUT: 6,     //5,0
            AGREPORT_RINGING: 20,   //20,0
            AGREPORT_PRECALL: 21,   //21,0
            AGREPORT_HOLD: 22,      //22,0
            AGREPORT_DIALING: 23,
            AGREPORT_OFFHOOK: 24,
            AGREPORT_HOLDDIALING: 25,
            AGREPORT_CONFERENCE: 26,
            AGREPORT_LISTEN: 27,
            AGREPORT_INTERCEPT: 28,
            AGREPORT_LISTENED: 29,
            AGREPORT_INTERCEPTED: 30,
            AGREPORT_MULTIMEDIA: 31,
            AGREPORT_HOLDTALKING: 32
        };
     */
    const CALLSTATEMAP = {
        1: AGSTATE.AS_RINGING,
        2: AGSTATE.AS_BUSY,
        3: AGSTATE.AS_HOLD,
        4: AGSTATE.AS_DIALING,
        32: AGSTATE.AS_HOLDTALKING,
        34: AGSTATE.AS_HOLDDIALING
    };

    return (function () {
        //0--unknown, 1--toinit, 2--initsucc, 3--initfail, 11--toconnectserver, 12--serverconnectsucc, 13--serverconnectfail, 21--toregisterdn 22--registerdnsucc, 23--registerdnfail, 31--toagentlogin, 32--agentloginsucc, 33--agentloginfail
        var m_softphonestep = 0,
            m_inittime = 0,
            m_logseq = 0,
            //m_serverEndpoint,
            m_OnSCTIEventListener = [],
            m_OnCTIEventListener = [],
            m_regcalls = {},
            m_ctiextras = {},

            ctitype = '',
            m_logoutconfirmoncall = 1,

            m_agent_login_guid = '',
            m_agent_status_guid = '',
            m_event_guid = '',
            m_to_save_event = 0,

            m_evtbak = '',
            m_OBCheckPhoneNo = 0,

            m_DBMASK = 0,
            m_masker = {},
            m_masker_event_ani = '',
            m_masker_event_dnis = '',
            m_masker_record_ani = '',
            m_masker_record_dnis = '',

            m_logintime,
            m_logouttime,

            m_dest = '',
            m_outphone = '',
            m_delayagentstate = '',
            m_delayagentmode = '',
            m_delayreasoncode = '',
            //keepAliveTimer = 0,
            statustimer = 0,
            //dataserviceTimer = 0,
            m_time = 0,
            m_statustimeout,

            m_timeout_login = 5000,

            m_sqlkey_event_insert = "softphone.event.insert.v202008",
            m_sqlkey_event_update = "softphone.event.update.v202008",
            m_sqlkey_event_updatecallstate = "softphone.event.updatecallstate.v202008",
            m_sqlkey_event_setevent = "softphone.event.setevent.v202008",

            m_save_logagentdateil = 1,
            m_save_logagentlogininfo = 1,
            //m_save_logcallinfo = 1,
            m_save_agentcurrentstate = 0,
            m_save_stagenttoday = 0,
            m_agent_stat = {},

            m_save_agentcall = 0,

            m_disableready = 0,
            m_disablereason = '',

            m_worktype = '',
            m_tmp_worktype = '',

            m_execseq = 0,
            m_sqlarr = [],

            m_conf = {};

        m_conf.m_defaultreasoncode = '';
        m_conf.m_report_always = 1;
        m_conf.m_report_dest = '';	//'6101',
        m_conf.m_report_keytoreport = '';
        m_conf.m_report_userdatas = '';	//'AgentID=[AgentID]|AutoComplete=1',
        m_conf.m_reportonsilentmonitored = 0;
        m_conf.m_reportdelayflag = false;
        m_conf.m_reportonrecorded = 0;

        m_conf.m_myd_dest = '';
        m_conf.m_myd_userdatas = '';	//'f_key=myd|Staff_ID=[Staff_ID]|Event_ID=[Event_GUID]|AgentID=[AgentID]|AutoComplete=1',

        m_conf.m_reopen = 0;

        m_conf.m_autoWorkMode = 2;
        m_conf.m_IBReleaseState = '';
        m_conf.m_OBReleaseState = '';
        m_conf.m_PreOBState = '';
        m_conf.m_PreOBReasonCode = '';

        m_conf.m_OBCallEndState = '';
        m_conf.m_OBCallEndReasonCode = '';
        m_conf.m_IBCallEndState = '';
        m_conf.m_IBCallEndReasonCode = '';
        m_conf.m_IBCallAbandonState = '';
        m_conf.m_IBCallAbandonReasonCode = '';

        m_conf.m_AutoAnswer = 0;
        m_conf.m_AutoAnswerDelay = 0;
        m_conf.m_AutoReleaseCall = 0;

        m_conf.m_AutoWorkEndForInbound = 0;
        m_conf.m_AutoWorkEndForOutbound = 0;
        m_conf.m_AutoWorkEndDelayForInbound = 0;
        m_conf.m_AutoWorkEndDelayForOutbound = 0;

        m_conf.m_MakeCallOnReady = 1;
        m_conf.m_MakeCallOnNotReady = 1;

        m_conf.m_canlogoutinwork = 0;

        m_conf.m_dnlist = '';					//^[2-8][0-9]{1,4}$
        m_conf.m_autoprefix = '';				//9
        m_conf.m_removeprefix = 0;
        m_conf.m_removeprefixlist = [];

        m_conf.m_DataUpdateAcceptedForDN = '';
        m_conf.m_DNISAsANIOnPDS = 0;

        m_conf.m_areacode = '';
        m_conf.m_keepalive = 5000;	//keepalive in seconds


        m_conf.m_ctidatkey = '';

        m_conf.m_transferondialinghold = true;

        m_conf.m_transfer_defaultdata = 'E_Dest|Staff_ID';
        m_conf.m_calloutdata = undefined;

        m_conf.m_defaultpassword = '';


        m_conf.m_ani = 'originalani';
        m_conf.m_dnis = 'originaldnis';
        m_conf.traninternalani = '';

        var startstatustimer = function () {
            if (!m_statustimeout) {
                return;
            }
            stopstatustimer();
            m_time = 0;
            var m_state = $SC.agentState;
            var m_mode = $SC.agentMode;
            var state;
            if (m_state == 2) {
                state = 'Ready';
            } else if (m_state == 3) {
                if (m_mode == 4) {
                    state = 'ACW';
                } else {
                    state = 'NotReady';
                }
            }
            if (!m_statustimeout[state]) {
                return;
            }
            statustimer = setInterval(function () {
                m_time++;
                if (m_statustimeout[state].timeout <= m_time) {
                    m_time = 0;
                    var nextstatus = m_statustimeout[state].nextstatus;
                    if (nextstatus == 'Ready') {
                        logmsg("try to change state by statustimeout");
                        $SC.agentReady(2, {nodelay: 1});
                    } else if (nextstatus == 'NotReady') {
                        logmsg("try to change state by statustimeout");
                        $SC.agentNotReady(3, {nodelay: 1});
                    }
                }
            }, 1000);
        };
        var stopstatustimer = function () {
            if (statustimer) {
                clearInterval(statustimer);
                statustimer = 0;
            }
        };

        //CompleteTransferWhenDialing, CompleteTransferWhenNR, CompleteTransferWhenRB, CompleteTransferWhenEstablish, and same for CompleteConference
        var f_autocomplete = "",
            conn_autocomplete = "";

        function CallStats() {
            this.TotalIB = 0;
            this.TotalIBAnswered = 0;
            this.TotalIBDuration = 0;
            this.TotalOB = 0;
            this.TotalOBReached = 0;
            this.TotalOBDuration = 0;
        }

        CallStats.prototype = {
            AddCallInfo: function () {
                var dur = 0;
                if ($SC.CallInfo.EstablishTime) {
                    try {
                        var d1 = new Date($SC.CallInfo.EstablishTime);
                        var d2 = new Date($SC.CallInfo.EndTime);
                        dur = Math.floor((d2.valueOf() - d1.valueOf()) / 1000);
                        if (dur > 0) {

                        } else {
                            dur = 0;
                        }
                    } catch (e) {
                        dur = -1;
                    }
                } else {
                    dur = -1;
                }
                if ($SC.CallInfo.CallType == 2) {
                    this.TotalIB += 1;
                    if (dur >= 0) {
                        this.TotalIBAnswered++;
                        this.TotalIBDuration += dur;
                    }
                } else {
                    this.TotalOB += 1;
                    if (dur >= 0) {
                        this.TotalOBReached++;
                        this.TotalOBDuration += dur;
                    }
                }
            }
        };

        function CallInfos() {

            this.Event_GUID = '';
            this.CallState = 0;
            this.CallState2 = 0;
            this.StateTime = undefined;
            this.transferflag = 0;
            this.transferdest = '';
            this.transferresult = 0;
            this.ANI = '';
            this.DNIS = '';
            this.CallType = 0;
            this.StartTime = undefined;
            this.EstablishTime = undefined;
            this.EndTime = undefined;
            this.hangupType = '1';
            this.m_Calllist = {};
            this.m_Event = {};
            this.m_agentcall = {};
            this.CallParty = {};
            this.m_agentcall.connectionid = "";
            this.m_agentcall.failreason = "";
            this.m_agentcall.otherdn = "";
            this.m_agentcall.thirdpartydn = "";
            this.m_agentcall.holdcount = 0;
            this.m_agentcall.holdduration = 0;
            this.m_agentcall.ringduration = 0;
            this.m_agentcall.talkduration = 0;
            this.m_agentcall.subcallcount = 0;
            this.m_agentcall.subcallduration = 0;
            this.m_agentcall.subcallret = 0;
            this.m_agentcall.skillgroup = "";
            this.m_agentcall.avalue1 = "";
            this.m_agentcall.avalue2 = "";
            this.m_agentcall.avalue3 = "";
            this.m_agentcall.avalue4 = "";
            this.m_agentcall.avalue5 = "";
            this.m_agentcall.firstrec_guid = "";
            this.m_agentcall.prevrec_guid = "";

            this.m_agentcall.m_holdtime = undefined;
            this.m_agentcall.m_ringtime = undefined;
            this.m_agentcall.m_talktimetime = undefined;

            this.m_userdatas = undefined;
            this.m_UCIDs = '';
            this.m_UCID0 = '';
            this.m_UCIDP = '';
            this.m_UCIDN = '';

            this.rawattachdata = undefined;
            this.OtherDN = undefined;
            this.CallType = '';
            this.IsTranIn = undefined;
            this.IsTranOut = undefined;

            this.CallID2 = undefined;
            this.CallID1 = undefined;

        }

        CallInfos.prototype = {
            AttachData: function (data) {
                if (!data) {
                    return;
                }

                var oneval;
                if (data == "^JSON^") {
                    var alldata = {};
                    if (this.m_userdatas) {
                        for (let vkey in this.m_userdatas) {
                            oneval = this.m_userdatas[vkey];
                            if (typeof (oneval) == 'object') {
                                if (oneval.hasOwnProperty('value')) {
                                    alldata[vkey] = oneval.value;
                                } else {
                                    alldata[vkey] = JSON.stringify(oneval);
                                }
                            } else {
                                alldata[vkey] = oneval;
                            }
                        }
                    }
                    return alldata;
                }
                if (this.m_userdatas) {
                    if (data.toLowerCase().substr(0,4) === "ucid") {
                        logmsg("UCID0=" + this.m_UCID0 + ",UCIDP=" + this.m_UCIDP + ",UCIDN=" + this.m_UCIDN + ",UCIDS=" + this.m_UCIDs);
                    }
                    if (data.toLowerCase() === "ucids") {
                        return this.m_UCIDs;
                    } else if (data.toLowerCase() === "ucid0") {
                        return this.m_UCID0;
                    } else if (data.toLowerCase() === "ucidp" || data.toLowerCase() === "ucid") {
                        return this.m_UCIDP || this.m_UCIDN;
                    } else if (data.toLowerCase() === "ucidn" || data.toLowerCase() === "ucidl") {
                        this.m_UCIDN;
                    }
                    //if (this.m_userdatas[data]) {
                    //	return this.m_userdatas[data].value;
                    //}
                    for (let vkey in this.m_userdatas) {
                        if (vkey.toLowerCase() == data.toLowerCase()) {
                            oneval = this.m_userdatas[vkey];
                            if (typeof (oneval) == 'object') {
                                if (oneval.hasOwnProperty('value')) {
                                    return oneval.value;
                                } else {
                                    return JSON.stringify(oneval);
                                }
                            } else {
                                return oneval;
                            }
                            //return this.m_userdatas[vkey].value;
                        }
                    }
                }
            },

            attachData: function (data) {
                return this.AttachData(data);
            },

            attachdata: function (data) {
                return this.AttachData(data);
            },

            removedata: function (data) {
                if (this.m_userdatas) {
                    for (let v in this.m_userdatas) {
                        if (v.toLowerCase() == data.toLowerCase()) {
                            logmsg('[testtest] remove userdata ' + v);
                            delete this.m_userdatas[v];
                        }
                    }
                    //delete this.m_userdatas[data];
                }
            },

            changeCall: function (datas) {
                var activeconn = '', heldconn = '';
                var t = this;
                try {
                    activeconn = datas.activecallid.value;
                    heldconn = datas.heldcallid.value;
                    logmsg("::changeCall: " + heldconn + ", " + activeconn);
                    for (let x in t.m_Calllist) {
                        //tbd201906
                        var call = t.m_Calllist[x];
                        if (call.connectionid == heldconn) {
                            call.connectionid = activeconn;
                            delete t.m_Calllist[x];
                            t.m_Calllist[activeconn] = call;
                        }
                        if (call.anotherconn == heldconn) {
                            call.anotherconn = activeconn;
                        }
                    }
                } catch (e) {

                }
            },

            addCall: function (datas) {
                var conn = '';
                var t = this;
                var evttime;

                if (datas.silentmonitor) {
                    if (datas.silentmonitor.value == 1) {
                        if (m_conf.m_reportdelayflag) {
                            if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_ESTABLISH) {
                                m_conf.m_reportdelayflag = false;
                                $SC.toReportAgent();
                            }
                        }
                        //$SC.addconsolelog("::addCall, silentmonitor, ignored");
                        //return -1;
                        if ($SC.CallInfo.CallState2 === 0) {
                            logmsg("::new call with silentmonitor, should be listen etc monitor functions")
                        } else {
                            logmsg("::addcall, silentmonitor, event + 10000");
                            datas.event.value = 10000 + parseInt(datas.event.value);
                            return 1000;
                        }
                    }
                }

                if (datas.connectionid) {
                    conn = datas.connectionid.value;
                } else if (datas.callid) {
                    conn = datas.callid.value;
                }
                //if (!conn) {
                if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_DATAUPDATED || parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RINGBACK) {

                    if (m_conf.m_DataUpdateAcceptedForDN && datas.releasingdevice) {
                        var rd = datas.releasingdevice.value;
                        if (rd) {
                            var reg = new RegExp(m_conf.m_DataUpdateAcceptedForDN);
                            if (reg.test(rd)) {

                            } else {
                                logmsg('::EVT_DATAUPDATED ignored for releasingdevice = ' + rd);
                                return -1;
                            }
                        }
                    }

                    var tdatas;
                    if (datas.userdata) {
                        tdatas = datas.userdata.value;
                    }
                    if (tdatas) {
                        if (!t.m_userdatas) {
                            t.m_userdatas = tdatas;
                        } else {
                            for (let x in tdatas) {
                                t.m_userdatas[x] = tdatas[x];
                            }
                        }
                        if (t.m_userdatas['ucid']) {
                            var tucid = t.m_userdatas['ucid'].value;
                            if (tucid) {
                                if (!t.m_UCID0) {
                                    t.m_UCID0 = tucid;
                                }
                                if (!t.m_UCIDP) {
                                    t.m_UCIDP = t.m_UCID0;
                                }
                                t.m_UCIDN = tucid;
                                if (!t.m_UCIDs) {
                                    t.m_UCIDs = tucid;
                                } else if (t.m_UCIDs.indexOf(tucid) < 0) {
                                    t.m_UCIDs = t.m_UCIDs + '|' + tucid;

                                }
                            }
                        }
                    }
                    if (m_conf.m_ctidatkey && t.m_userdatas) {
                        //t.m_Event.attacheddata = t.AttachData(m_conf.m_ctidatkey) || "";
                        /*
                        if (t.m_Event && !t.m_Event[m_conf.m_ctidatkey] && t.m_userdatas[m_conf.m_ctidatkey]) {
                            if (m_conf.m_ctidatkey.toLowerCase() == 'ucid' && t.m_UCID0) {
                                t.m_Event.attacheddata = t.m_UCID0;
                            } else {
                                t.m_Event.attacheddata = t.m_userdatas[m_conf.m_ctidatkey].value;
                            }
                        }
                         */
                    }
                    return;
                }
                //}
                if (!conn) {
                    return;
                }

                if (!this.m_Calllist) {
                    t.clear();
                }
                var call = this.m_Calllist[conn];
                var icallstate = 0,
                    icallstate2 = 0,
                    icallstep = 0;
                if (!call) {
                    call = {};
                    call.connectionid = conn;
                    call.anotherconn = '';
                    call.held = 0;
                    call.connected = 0;
                    call.callstate = 0;
                    evttime = $SC.getservertime(datas);	// datas.servertime.value;
                    call.starttime = evttime;

                    if (datas.prevconnectionid) {
                        call.anotherconn = datas.prevconnectionid.value;
                    }
                    t.m_Calllist[conn] = call;
                    logmsg('__SoftphoneCore__, CallList, in addCall() add ' + conn + ', ' + $SC.dumpcalllist());
                }

                if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_CONFERENCED && call.anotherconn) {
                    if (call.anotherconn == datas.prevconnectionid.value) {
                        call.callstate = $CTI_CONST.CALL_STATE.CS_TALKING;
                        call.connected = 1;
                        t.CallState = call.callstate;
                        t.CallState2 = call.callstate;

                        //conn: datas.conn, acon1: datas.prev, acon2: datas.prev.prev
                        var acon1 = call.anotherconn;
                        var acon2 = '';
                        var tcallanother = t.m_Calllist[acon1];

                        logmsg('::con=' + call.connectionid + ',con1=' + acon1);
                        if (tcallanother) {
                            acon2 = tcallanother.anotherconn;
                            logmsg('[' + acon1 + '] found, con2=' + acon2);
                            if (acon2 == conn) {
                                acon2 = '';
                            }
                            //t.CallState2 = $CTI_CONST.CALL_STATE.CS_TALKINGHELD;
                        } else {
                            logmsg('[' + acon1 + '] not found');
                        }

                        logmsg('::before replace, ' + $SC.dumpcalllist());
                        call.anotherconn = acon2;
                        for (var x in t.m_Calllist) {
                            var tc = t.m_Calllist[x];
                            if (tc.anotherconn == acon1) {
                                if (tc.connectionid == conn) {
                                    tc.anotherconn = acon2;
                                    if (t.CallState2 == $CTI_CONST.CALL_STATE.CS_TALKING) {
                                        t.CallState2 = $CTI_CONST.CALL_STATE.CS_TALKINGHELD;
                                    } else {
                                        t.CallState2 = $CTI_CONST.CALL_STATE.CS_DIALINGHELD;
                                    }
                                } else {
                                    tc.anotherconn = conn;
                                }
                            }
                        }

                        logmsg('::after replace, ' + $SC.dumpcalllist());

                        if (t.m_Calllist[datas.prevconnectionid.value]) {
                            delete t.m_Calllist[datas.prevconnectionid.value];
                            logmsg('__SoftphoneCore__, CallList, in addCall() delete ' + datas.prevconnectionid.value + ', ' + $SC.dumpcalllist());
                            evttime = $SC.getservertime(datas);
                            $SC.fireSCTIEvent('callstatechange', undefined, evttime);
                        } else {
                            logmsg('__SoftphoneCore__, CallList, in addCall() no delete ' + datas.prevconnectionid.value + ', ' + $SC.dumpcalllist());
                        }
                    }
                }

                switch (parseInt(datas.event.value)) {
                    case $CTI_CONST.CTI_MSG.EVT_RINGING:		//1
                        icallstate = $CTI_CONST.CALL_STATE.CS_RINGING;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_DIALING:		//20
                        icallstate = $CTI_CONST.CALL_STATE.CS_DIALING;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:		//2
                    case 52:									//EVT_TREATMENTAPPLIED=52;
                        icallstate = $CTI_CONST.CALL_STATE.CS_TALKING;
                        call.connected = 1;
                        if (!call.establishtime) {
                            evttime = $SC.getservertime(datas);	// datas.servertime.value;
                            call.establishtime = evttime;
                        }
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_HELD:			//6
                        icallstate = $CTI_CONST.CALL_STATE.CS_HELD;
                        call.held = 1;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_RETRIEVED:		//7
                        if (!call.connected) {
                            icallstate = $CTI_CONST.CALL_STATE.CS_DIALING;
                        } else {
                            icallstate = $CTI_CONST.CALL_STATE.CS_TALKING;
                        }
                        call.held = 0;
                            t.transferflag = 0;
                        break;
                    //case $CTI_CONST.CTI_MSG.EVT_CONFERENCED:	//21
                    //t.CallState = call.callstate;
                    //t.CallState2 = call.callstate;
                    //$SC.fireSCTIEvent('callstatechange');
                    //break;
                    default:
                }

                if (icallstate > 0) {
                    if (!call.callstate || call.callstate != icallstate) {
                        if (icallstate) {
                            call.callstate = icallstate;
                            icallstate2 = icallstate;

                            if (call.anotherconn) {
                                var anothercall = this.m_Calllist[call.anotherconn];
                                if (anothercall) {
                                    anothercall.anotherconn = conn;
                                    switch (icallstate) {
                                        case $CTI_CONST.CALL_STATE.CS_TALKING:
                                            icallstate2 = $CTI_CONST.CALL_STATE.CS_TALKINGHELD;
                                            break;
                                        case $CTI_CONST.CALL_STATE.CS_DIALING:
                                            icallstate2 = $CTI_CONST.CALL_STATE.CS_DIALINGHELD;
                                            break;
                                        case $CTI_CONST.CALL_STATE.CS_HELD:
                                            if (anothercall.callstate == $CTI_CONST.CALL_STATE.CS_TALKING) {
                                                icallstate2 = $CTI_CONST.CALL_STATE.CS_TALKINGHELD;
                                            } else {
                                                icallstate2 = $CTI_CONST.CALL_STATE.CS_HELD;
                                            }
                                            break;
                                        default:
                                            break;
                                    }
                                }
                            }

                            t.CallState = icallstate;
                            t.CallState2 = icallstate2;
                        }

                        var tdatas;
                        var tucid;
                        if (!t.StartTime) {
                            icallstep = 1;
                            t.StartTime = call.starttime;
                            if (datas.userdata) {
                                t.m_userdatas = datas.userdata.value;
                            }
                            if (t.m_userdatas && t.m_userdatas['ucid']) {
                                tucid = t.m_userdatas['ucid'].value;
                            }
                        } else {
                            //var tdatas;
                            if (datas.userdata) {
                                tdatas = datas.userdata.value;
                            }
                            if (tdatas) {
                                if (!t.m_userdatas) {
                                    t.m_userdatas = tdatas;
                                } else {
                                    for (let x in tdatas) {
                                        t.m_userdatas[x] = tdatas[x];
                                    }
                                }
                                if (t.m_userdatas['ucid']) {
                                    tucid = t.m_userdatas['ucid'].value;
                                }
                            }
                        }
                                //var tucid = t.m_userdatas['ucid'].value;
                        if (tucid) {
                            if (!t.m_UCID0) {
                                t.m_UCID0 = tucid;
                            }
                            if (!t.m_UCIDP) {
                                t.m_UCIDP = t.m_UCID0;
                            }
                            t.m_UCIDN = tucid;
                            if (!t.m_UCIDs) {
                                t.m_UCIDs = tucid;
                            } else if (t.m_UCIDs.indexOf(tucid) < 0) {
                                t.m_UCIDs = t.m_UCIDs + '|' + tucid;
                            }
                            //if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_PARTYCHANGED) {
                            //    t.m_UCIDP = tucid;
                            //}
                        }

                        if (m_conf.m_ctidatkey && t.m_userdatas) {
                            //t.m_Event.attacheddata = t.AttachData(m_conf.m_ctidatakey);
                            /*
                            if (t.m_Event && !t.m_Event[m_conf.m_ctidatkey] && t.m_userdatas[m_conf.m_ctidatkey]) {
                                //t.m_Event.attacheddata = t.m_userdatas[m_conf.m_ctidatkey].value;
                                if (m_conf.m_ctidatkey.toLowerCase() == 'ucid' && t.m_UCID0) {
                                    t.m_Event.attacheddata = t.m_UCID0;
                                } else {
                                    t.m_Event.attacheddata = t.m_userdatas[m_conf.m_ctidatkey].value;
                                }
                            }
                             */
                        }
                        if (icallstate2 == $CTI_CONST.CALL_STATE.CS_TALKING && !this.EstablishTime) {
                            icallstep = 2;
                            t.EstablishTime = call.establishtime;
                        }

                        var conn1 = call.anotherconn;
                        if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_DIALING) {
                            if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
                                if (f_autocomplete == 'completetransferwhendialing') {
                                    f_autocomplete = '';
                                    $SC.completeTransfer();
                                } else if (f_autocomplete == 'completeconferencewhendialing') {
                                    f_autocomplete = '';
                                    $SC.completeConference();
                                }
                            }
                        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_NETWORKREACHED) {
                            if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
                                if ((f_autocomplete == 'completetransferwhendialing') || (f_autocomplete == 'completetransferwhennr')) {
                                    f_autocomplete = '';
                                    $SC.completeTransfer();
                                } else if ((f_autocomplete == 'completeconferencewhendialing') || (f_autocomplete == 'completeconferencewhennr')) {
                                    f_autocomplete = '';
                                    $SC.completeConference();
                                }

                            }
                        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_RINGBACK) {
                            if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
                                if ((f_autocomplete == 'completetransferwhendialing') || (f_autocomplete == 'completetransferwhennr') || (f_autocomplete == 'completetransferwhenrb')) {
                                    f_autocomplete = '';
                                    $SC.completeTransfer();
                                } else if ((f_autocomplete == 'completeconferencewhendialing') || (f_autocomplete == 'completeconferencewhennr') || (f_autocomplete == 'completeconferencewhenrb')) {
                                    f_autocomplete = '';
                                    $SC.completeConference();
                                }

                            }
                        } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_ESTABLISH) {
                            if (conn1 && (conn1 == conn_autocomplete || conn == conn_autocomplete)) {
                                if ((f_autocomplete == 'completetransferwhendialing') || (f_autocomplete == 'completetransferwhennr') || (f_autocomplete == 'completetransferwhenrb') || (f_autocomplete == 'completetransferwhenestablish')) {
                                    f_autocomplete = '';
                                    $SC.completeTransfer();
                                } else if ((f_autocomplete == 'completeconferencewhendialing') || (f_autocomplete == 'completeconferencewhennr') || (f_autocomplete == 'completeconferencewhenrb') || (f_autocomplete == 'completeconferencewhenestablish')) {
                                    f_autocomplete = '';
                                    $SC.completeConference();
                                }
                            }
                        }

                        //$SC.fireSCTIEvent('callstatechange');

                        var m_Event = t.m_Event;
                        if (icallstep == 1) {
                            /*        					if (call.userdatas) {
        						this.m_userdatas = JSON.parse(call.userdatas);
        					}
*/
                            if (icallstate == $CTI_CONST.CALL_STATE.CS_RINGING) {
                                t.CallType = $CTI_CONST.CALL_TYPE.CT_INBOUND;
                                if ($SC.CallInfo.AttachData("pdstype")) {
                                    t.CallType = $CTI_CONST.CALL_TYPE.CT_OUTBOUND + 3;
                                }
                            } else if (icallstate == $CTI_CONST.CALL_STATE.CS_DIALING) {
                                t.CallType = $CTI_CONST.CALL_TYPE.CT_OUTBOUND;
                            } else if (ANI == $SC.dn) {
                                t.CallType = $CTI_CONST.CALL_TYPE.CT_OUTBOUND;
                            } else {
                                t.CallType = $CTI_CONST.CALL_TYPE.CT_INBOUND;
                            }

                            if (m_conf.m_ani && this.m_userdatas && this.m_userdatas[m_conf.m_ani]) {
                                t.ANI = this.m_userdatas[m_conf.m_ani].value;
                            } else if (m_conf.m_ani && datas[m_conf.m_ani]) {
                                t.ANI = datas[m_conf.m_ani].value;
                            } else if (datas.ani) {
                                t.ANI = datas.ani.value;
                            }
                            if (m_conf.m_dnis && this.m_userdatas && this.m_userdatas[m_conf.m_dnis]) {
                                t.DNIS = this.m_userdatas[m_conf.m_dnis].value;
                            } else if (m_conf.m_dnis && datas[m_conf.m_dnis]) {
                                t.DNIS = datas[m_conf.m_dnis].value;
                            } else if (datas.dnis) {
                                t.DNIS = datas.dnis.value;
                            }
                            if (!this.ANI || this.ANI == 'null') {
                                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                                    if (datas.otherdn) {
                                        t.ANI = datas.otherdn.value;
                                    }
                                } else {
                                    if (datas.thisdn) {
                                        t.ANI = datas.thisdn.value;
                                    } else {
                                        t.ANI = $SC.dn;
                                    }
                                }
                                if (this.ANI == 'null') {
                                    this.ANI = $SC.dn;
                                }
                            }
                            if (!t.DNIS || this.DNIS == 'null') {
                                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                                    if (datas.thisdn) {
                                        t.DNIS = datas.thisdn.value;
                                        if (this.DNIS == 'null') {
                                            this.DNIS = $SC.dn;
                                        }
                                    } else {
                                        t.DNIS = $SC.dn;
                                    }
                                } else {
                                    if (datas.otherdn) {
                                        t.DNIS = datas.otherdn.value;
                                        if (this.DNIS == 'null') {
                                            this.DNIS = m_outphone;
                                        }
                                    } else {
                                        t.DNIS = m_outphone;
                                    }
                                }
                            }

                            if (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
                                t.DNIS = $SC.removeprefix(t.DNIS);
                            }

                            if (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND + 3 && m_conf.m_DNISAsANIOnPDS == 1) {
                                var tani = t.ANI;
                                t.ANI = t.DNIS;
                                t.DNIS = tani;
                            };

                            t.m_Event = {};
                            m_Event = t.m_Event;
                            //with (m_Event)
                            //{
                            //Event_GUID,CallType,Customer_GUID,DNIS,ANI,AgentID,Extension,CallStartTime,CallEndTime,TransferFrom,TransfterTo
                            //,CallBeginTime,CallEstablished,HangupType,WorkStartTime,WorkEndTime,StringField1,HandleBy_ID,HandleGroup_ID
                            //,Record_GUID,AttachedData,StringField2,comments,contact_customer_guid

                            m_Event.event_guid = Guid.raw();
                            t.Event_GUID = m_Event.event_guid;
                            m_Event.ani = t.ANI;
                            m_Event.dnis = t.DNIS;
                            if (t.CallType ==  $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
                                m_Event.calltype = "2";
                            } else if (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND + 3) {
                                m_Event.calltype = "4"
                            } else {
                                m_Event.calltype = "1";
                            }

                            if ($SC.CallInfo.monitorcall) {
                                m_Event.calltype = "8";
                            }

                            //m_Event.calltype = (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) ? '2' : '1';
                            m_Event.agentid = $SC.agentId;
                            m_Event.extension = $SC.dn;
                            m_Event.handleby_id = $E.staff.id;
                            m_Event.handlegroup_id = $E.staff.current.groupId;
                            m_Event.record_guid = '';

                            m_Event.callstarttime = t.StartTime;	//this.StartTime.format('yyyy-MM-dd hh:mm:ss');
                            m_Event.callendtime = m_Event.callstarttime;
                            m_Event.callbegintime = m_Event.callstarttime;
                            m_Event.transferfrom = '';
                            m_Event.transferto = '';

                            m_Event.customer_guid = '';
                            m_Event.customername = '';
                            m_Event.comments = '';
                            m_Event.contact_customer_guid = '';

                            if (m_conf.m_ctidatkey) {
                                //m_Event.attacheddata = t.AttachData(m_conf.ctidatkey) || "";
                            }
                            /*
                            if (t.m_userdatas && m_conf.m_ctidatkey && t.m_userdatas[m_conf.m_ctidatkey]) {
                                m_Event.attacheddata = t.m_userdatas[m_conf.m_ctidatkey].value;
                            } else {
                                m_Event.attacheddata = '';
                            }
                             */
                            m_Event.record_guid = '';
                            m_Event.stringfield1 = 'jssoftphone';
                            m_Event.stringfield2 = ctitype;

                            m_Event.workstarttime = m_Event.callstarttime;
                            m_Event.workendtime = m_Event.callendtime;
                            m_Event.hangupType = '1';
                            t.hangupType = m_Event.hangupType;
                            m_Event.callestablished = 0;

                            //}
                            $SC.setRecordInfo();
                            if (t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                                m_Event.transferfrom = t.AttachData('Staff_ID');
                                if (!m_Event.transferfrom) {
                                    m_Event.transferfrom = '';
                                }
                                if (m_conf.m_AutoAnswer == 1) {
                                    $SC.doautoanswer();
                                }
                            }


                            //t.saveEvent(1);
                            m_to_save_event = 1;
                            m_outphone = '';
                            stopstatustimer();

                            m_conf.m_reportdelayflag = false;
                            if (m_conf.m_NoCallDisconnectIB == 1 && t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                                $SC.agentNotReady(5, {nodelay: 1});
                            } else if (m_conf.m_NoCallDisconnectOB == 1 && t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
                                $SC.agentNotReady(5, {nodelay: 1});
                            }
                            $SC.fireSCTIEvent('OnCallStart');
                            //$SC.fireSCTIEvent('callstatechange');
                        } else {
                            //var tdatas = call.userdatas;
                            if (icallstep == 2) {
                                if (m_Event) {
                                    //with (m_Event) {
                                    m_Event.callestablished = 1;
                                    m_Event.callestablishtime = this.EstablishTime;//this.EstablishTime.format('yyyy-MM-dd hh:mm:ss');
                                    m_Event.callbegintime = m_Event.callestablishtime;
                                    m_Event.callendtime = m_Event.callestablishtime;
                                    //}
                                }
                                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                                    if (m_conf.m_reportonsilentmonitored != 1 && m_conf.m_reportonrecorded !=1) {
                                        $SC.toReportAgent();
                                    } else {
                                        m_conf.m_reportdelayflag = true;
                                        setTimeout(function () {
                                            if (m_conf.m_reportdelayflag) {
                                                m_conf.m_reportdelayflag = false;
                                                $SC.toReportAgent();
                                            }
                                        }, 1000);
                                    }
                                }
                                this.updateEventCallState();
                                $SC.fireSCTIEvent('OnCallEstablish');
                            }
                        }
                        if (!evttime) {
                            evttime = $SC.getservertime(datas);
                        }

                        //Call Party

                        switch (parseInt(datas.event.value)) {
                            case $CTI_CONST.CTI_MSG.EVT_DIALING:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_RELEASED:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_CONFERENCED:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_PARTYDELETED:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_PARTYCHANGED:
                                break;
                            case $CTI_CONST.CTI_MSG.EVT_PARTYADDED:
                                break;
                        }

                        $SC.fireSCTIEvent('callstatechange', undefined, evttime);
                    }
                }
            },
            removeCall: function (datas) {
                var conn = '';
                var icallstate = 0;
                var icallstate2 = 0;
                var evttime = undefined;

                var t = this;

                if (datas.connectionid) {
                    conn = datas.connectionid.value;
                } else if (datas.callid) {
                    conn = datas.callid.value;
                }
                if (!conn) {
                    return;
                }

                for (var x in t.m_Calllist) {
                    var call = t.m_Calllist[x];

                    if (!call) {
                        return;
                    }

                    if (call.anotherconn == conn) {
                        call.anotherconn = '';
                        icallstate = call.callstate;
                    }
                    if (call.connectionid == conn) {
                        delete this.m_Calllist[conn];
                        logmsg('__SoftphoneCore__, CallList, in removeCall() delete ' + conn + ', ' + $SC.dumpcalllist());
                    }
                    icallstate2 = icallstate;
                }

                t.CallState = icallstate;
                t.CallState2 = icallstate;

                //if (t.transferflag != 0 && t.CallState2 != 32 && t.CallState2 != 34) {
                //	t.transferflag = 0;
                //}

                //$SC.fireSCTIEvent('callstatechange');

                if (!icallstate) {
                    evttime = $SC.getservertime(datas);	// datas.servertime.value;
                    t.EndTime = evttime;

                    var e = t.m_Event;
                    if (e) {
                        //with (m_Event) {
                        e.callendtime = t.EndTime;	//this.EndTime.format('yyyy-MM-dd hh:mm:ss');
                        if (e.workendtime == e.workstarttime && e.callendtime > e.workstarttime) {
                            e.workendtime = e.callendtime;
                        }
                        //}
                    }
                    var itpreleased = 0;
                    if (datas) {
                        if (datas.tpreleased) {
                            itpreleased = 1;
                            if (t.transferflag == 1 || t.transferflag == 3) {
                                e.hangupType = '3';
                                t.hangupType = '3';
                                e.transferto = t.transferdest;
                            } else {
                                e.hangupType = '1';
                                e.transferto = '';
                                if (datas.tpreleased.value == 1) {
                                    e.hangupType = '2';
                                    t.hangupType = e.hangupType;
                                }
                            }
                        }
                    }
                    if (itpreleased == 0  && $SC.CallInfo.releaseaction) {
                        if (($SC.CallInfo.releaseaction.action == "releasecall") && (new Date().valueOf() - $SC.CallInfo.releaseaction.actiontime < 3000)) {
                            e.hangupType = '2';
                            t.hangupType = e.hangupType;
                        } else if (($SC.CallInfo.releaseaction.action == "mutetransfer" || $SC.CallInfo.releaseaction.action == "completetransfer") && (new Date().valueOf() - $SC.CallInfo.releaseaction.actiontime < 3000)) {
                            e.hangupType = '3';
                            t.hangupType = e.hangupType;
                        }
                    }
                    $SC.CallStat.AddCallInfo();
                    if (!evttime) {
                        evttime = $SC.getservertime(datas);
                    }
                    t.__agentcall(evttime);
                    t.saveEvent(2);
                    t.onCallEnd(this.m_Event);
                    $SC.fireSCTIEvent('OnCallEnd');
                }
                if (!evttime) {
                    evttime = $SC.getservertime(datas);
                }
                $SC.fireSCTIEvent('callstatechange', undefined, evttime);
            },
            getActiveCall: function () {
                for (var x in this.m_Calllist) {
                    if (this.m_Calllist[x].callstate == $CTI_CONST.CALL_STATE.CS_TALKING) {
                        return this.m_Calllist[x];
                    }
                }
            },
            getHeldCall: function () {
                for (var x in this.m_Calllist) {
                    if (this.m_Calllist[x].callstate == $CTI_CONST.CALL_STATE.CS_HELD) {
                        return this.m_Calllist[x];
                    }
                }
            },
            getDialingCall: function () {
                for (var x in this.m_Calllist) {
                    if (this.m_Calllist[x].callstate == $CTI_CONST.CALL_STATE.CS_DIALING) {
                        return this.m_Calllist[x];
                    }
                }
            },
            getRingingCall: function () {
                for (var x in this.m_Calllist) {
                    if (this.m_Calllist[x].callstate == $CTI_CONST.CALL_STATE.CS_RINGING) {
                        return this.m_Calllist[x];
                    }
                }
            },

//softphone.event.insert.v201610=INSERT INTO EVENT{C1}(Event_GUID,CallType,Customer_GUID,DNIS,ANI,AgentID,Extension,CallStartTime,CallEndTime,TransferFrom,TransfterTo,CallBeginTime,CallEstablished,HangupType,WorkStartTime,WorkEndTime,StringField1,HandleBy_ID,HandleGroup_ID,Record_GUID,AttachedData,StringField2,comments,contact_customer_guid{C26}) values(@{C2}S,@{C3}S,@{C4}S,@{C5}S,@{C6}S,@{C7}S,@{C8}S,@{C9}D,@{C10}D,@{C11}S,@{C12}S,@{C13}D,@{C14}N,@{C15}S,@{C16}D,@{C17}D,@{C18}S,@{C19}S,@{C20}S,@{C21}S,@{C22}S,@{C23}S,@{C24}S,@{C25}S{C27})
//softphone.event.insert.v201707=INSERT INTO EVENT{C1}(Event_GUID,CallType,Customer_GUID,DNIS,ANI,AgentID,Extension,CallStartTime,CallEndTime,TransferFrom,TransfterTo,CallBeginTime,CallEstablished,HangupType,WorkStartTime,WorkEndTime,StringField1,HandleBy_ID,HandleGroup_ID,Record_GUID,AttachedData,StringField2,comments,contact_customer_guid,connectionid,callresult_id,callresultreason_id,objectivestatus,transferresult{C31},ani_enc,dnis_enc) values(@{C2}S,@{C3}S,@{C4}S,@{C5}S,@{C6}S,@{C7}S,@{C8}S,@{C9}D,@{C10}D,@{C11}S,@{C12}S,@{C13}D,@{C14}N,@{C15}S,@{C16}D,@{C17}D,@{C18}S,@{C19}S,@{C20}S,@{C21}S,@{C22}S,@{C23}S,@{C24}S,@{C25}S,@{C26}S,@{C27}S,@{C28}S,@{C29}S,@{C30}N{C32},@{C33}S,@{C34}S)
//softphone.event.update.v201707=UPDATE EVENT{C1} set Customer_GUID=@{C3}S,contact_customer_guid=@{C4}S,CallStartTime=@{C5}D,CallEndTime=@{C6}D,WorkStartTime=@{C7}D,WorkEndTime=@{C8}D,CallEstablished=@{C9}N,HangupType=@{C10}S,TransferFrom=@{C11}S,TransfterTo=@{C12}S,Record_GUID=@{C13}S,AttachedData=@{C14}S,comments=@{C15}S,callresult_id=@{C16}S,callresultreason_id=@{C17}S,objectivestatus=@{C18}S,transferresult=@{C19}N{C20} where event_guid=@{C2}S
//softphone.event.insert.v202008=INSERT INTO EVENT{C1}(Event_GUID,CallType,Customer_GUID,DNIS,ANI,AgentID,Extension,CallStartTime,CallEndTime,TransferFrom,TransfterTo,CallBeginTime,CallEstablished,HangupType,WorkStartTime,WorkEndTime,StringField1,HandleBy_ID,HandleGroup_ID,Record_GUID,AttachedData,StringField2,comments,contact_customer_guid,connectionid,callresult_id,callresultreason_id,objectivestatus,transferresult{C31},ani_enc,dnis_enc,objective_guid,dynfield1,dynfield2,dynfield3,dynfield4,dynfield5) values(@{C2}S,@{C3}S,@{C4}S,@{C5}S,@{C6}S,@{C7}S,@{C8}S,@{C9}D,@{C10}D,@{C11}S,@{C12}S,@{C13}D,@{C14}N,@{C15}S,@{C16}D,@{C17}D,@{C18}S,@{C19}S,@{C20}S,@{C21}S,@{C22}S,@{C23}S,@{C24}S,@{C25}S,@{C26}S,@{C27}S,@{C28}S,@{C29}S,@{C30}N{C32},@{C33}S,@{C34}S,@{C35}S,@{C36}S,@{C37}S,@{C38}S,@{C39}S,@{C40}S)
// softphone.event.update.v202008=UPDATE EVENT{C1} set Customer_GUID=@{C3}S,contact_customer_guid=@{C4}S,CallStartTime=@{C5}D,CallEndTime=@{C6}D,WorkStartTime=@{C7}D,WorkEndTime=@{C8}D,CallEstablished=@{C9}N,HangupType=@{C10}S,TransferFrom=@{C11}S,TransfterTo=@{C12}S,Record_GUID=@{C13}S,AttachedData=@{C14}S,comments=@{C15}S,callresult_id=@{C16}S,callresultreason_id=@{C17}S,objectivestatus=@{C18}S,transferresult=@{C19}N{C20},objective_guid=@{C21}S,dynfield1=@{C22}S,dynfield2=@{C23}S,dynfield3=@{C24}S,dynfield4=@{C25}S,dynfield5=@{C26}S where event_guid=@{C2}S
// softphone.event.updatecallstate.v202008=UPDATE EVENT{C1} SET CallEstablished=1,CallStartTime=@{C3}D,CallEndTime=@{C4}D WHERE Event_GUID=@{C2}S
// softphone.event.setevent.v202008=UPDATE EVENT{C1} set Customer_GUID=@{C3}S,contact_customer_guid=@{C4}S,WorkStartTime=@{C5}D,WorkEndTime=@{C6}D,comments=@{C7}S,CallResult_ID=@{C8}S,CallResultReason_ID=@{C9}S,ObjectiveStatus=@{C10}S{C11},objective_guid=@{C12}S,dynfield1=@{C13}S,dynfield2=@{C14}S,dynfield3=@{C15}S,dynfield4=@{C16}S,dynfield5=@{C17}S where event_guid=@{C2}S

            //t: 1--insert, 2--update
            saveEvent: function (t) {

                if (m_to_save_event == 1 && t == 2) {
                    m_to_save_event = 0;
                    this.saveEvent(1);
                    return;
                }

                var e = this.m_Event;
                var e_connid = '';
                var e_callrid = e['callresult_id'] || '';
                var e_callrrid = e['callresultreason_id'] || '';
                var e_os = e['objectivestatus'] || '';
                var e_tr = 0;

                if (this.transferflag == 1 || this.transferflag == 3) {
                    if (!e.transferto && m_dest) {
                        e.transferto = m_dest;
                    }
                } else {
                    e.transferto = '';
                }
                if (e && e.event_guid) {
                    if (e.callendtime < e.callstarttime) {
                        e.callendtime = e.callstarttime;
                    }
                    /*
                    if (e.workendtime < e.workstarttime) {
                        if (e.workendtime == e.callstarttime) {
                            e.workendtime = e.callendtime;
                        } else {
                            e.workendtime = e.workstarttime;
                        }
                        if (e.workendtime < e.workstarttime) {
                            e.workendtime = e.workstarttime;
                        }
                    }
                     */
                    if (e.workendtime <= e.workstarttime) {
                        e.workendtime = e.callendtime;
                        if (e.workendtime < e.workstarttime) {
                            e.workendtime = e.workstarttime;
                        }
                    }
                    e.customer_guid = $SC.checkundefined(e.customer_guid);
                    e.customername = $SC.checkundefined(e.customername);
                    e.attacheddata = $SC.CallInfo.AttachData(m_conf.m_ctidatkey);
                    e.comments = $SC.checkundefined(e.comments);
                    e.stringfield2 = $SC.checkundefined(e.stringfield2);
                    e.contact_customer_guid = $SC.checkundefined(e.contact_customer_guid);
                    e.objectivestatus = $SC.checkundefined(e.objectivestatus);
                    e.callresult_id = $SC.checkundefined(e.callresult_id);
                    e.callresultreason_id = $SC.checkundefined(e.callresultreason_id);
                    e.objective_guid = $SC.checkundefined(e.objective_guid);
                    e.dynfield1 = $SC.checkundefined(e.dynfield1);
                    e.dynfield2 = $SC.checkundefined(e.dynfield2);
                    e.dynfield3 = $SC.checkundefined(e.dynfield3);
                    e.dynfield4 = $SC.checkundefined(e.dynfield4);
                    e.dynfield5 = $SC.checkundefined(e.dynfield5);

//logmsg("saveevent", t, e, JSON.stringify(e));
//logmsg("saveevent", $SC.CallInfo.m_Event, JSON.stringify($SC.CallInfo.m_Event));
                    if (t == 2) {
                        $SC.executeupdate(m_sqlkey_event_update
                            , [$E.staff.epidSql, e.event_guid, e.customer_guid, e.contact_customer_guid
                                , e.callstarttime, e.callendtime, e.workstarttime, e.workendtime
                                , e.callestablished, e.hangupType, e.transferfrom, e.transferto
                                , e.record_guid, e.attacheddata, e.comments
                                , e_callrid, e_callrrid, e_os, e_tr, '',e.objective_guid, e.dynfield1, e.dynfield2, e.dynfield3, e.dynfield4, e.dynfield5]
                            , 'async: true');
                        if (m_evtbak) {
                            $SC.executeupdate(m_sqlkey_event_update.replace(".event.", "." + m_evtbak + ".")
                                , [$E.staff.epidSql, e.event_guid, e.customer_guid, e.contact_customer_guid
                                    , e.callstarttime, e.callendtime, e.workstarttime, e.workendtime
                                    , e.callestablished, e.hangupType, e.transferfrom, e.transferto
                                    , e.record_guid, e.attacheddata, e.comments
                                    , e_callrid, e_callrrid, e_os, e_tr, '',e.objective_guid, e.dynfield1, e.dynfield2, e.dynfield3, e.dynfield4, e.dynfield5]
                                , 'async: true');
                        }
                        $SC.fireSCTIEvent('saveevent');
                    } else {
                        $SC.executeupdate(m_sqlkey_event_insert
                            , [$E.staff.epidSql, e.event_guid, e.calltype, e.customer_guid
                                , $SC.getdbmask(e.dnis, 'event', 'dnis'), $SC.getdbmask(e.ani, 'event', 'ani'), e.agentid, e.extension, e.callstarttime, e.callendtime
                                , e.transferfrom, e.transferto, e.callbegintime, e.callestablished, e.hangupType
                                , e.workstarttime, e.workendtime, e.stringfield1, e.handleby_id, e.handlegroup_id
                                , e.record_guid, e.attacheddata, e.stringfield2, e.comments, e.contact_customer_guid
                                , e_connid, e_callrid, e_callrrid, e_os, e_tr, '', '', $SC.getdbenc(e.dnis), $SC.getdbenc(e.ani)
                                , e.objective_guid, e.dynfield1, e.dynfield2, e.dynfield3, e.dynfield4, e.dynfield5]
                            , 'async: true');
                        e._saveflag = 1;
                        if (m_evtbak) {
                            $SC.executeupdate(m_sqlkey_event_insert.replace(".event.", "." + m_evtbak + ".")
                                , [$E.staff.epidSql, e.event_guid, e.calltype, e.customer_guid
                                    , $SC.getdbmask(e.dnis, m_evtbak, 'dnis'), $SC.getdbmask(e.ani, m_evtbak, 'ani'), e.agentid, e.extension, e.callstarttime, e.callendtime
                                    , e.transferfrom, e.transferto, e.callbegintime, e.callestablished, e.hangupType
                                    , e.workstarttime, e.workendtime, e.stringfield1, e.handleby_id, e.handlegroup_id
                                    , e.record_guid, e.attacheddata, e.stringfield2, e.comments, e.contact_customer_guid
                                    , e_connid, e_callrid, e_callrrid, e_os, e_tr, '', '', $SC.getdbenc(e.dnis), $SC.getdbenc(e.ani)
                                    , e.objective_guid, e.dynfield1, e.dynfield2, e.dynfield3, e.dynfield4, e.dynfield5]
                                , 'async: true');
                        }
                    }
                    if (m_save_agentcall == 1) {
                        this.saveAgentCall(t)
                    }
                }
            },

//softphone.event.updatecallstate.v201707=UPDATE EVENT{C1} SET CallEstablished=1,CallStartTime=@{C3}D,CallEndTime=@{C4}D WHERE Event_GUID=@{C2}S
            updateEventCallState: function () {
                var e = this.m_Event;
                //with (m_Event){
                if (e && e.event_guid && e._saveflag) {
                    $SC.executeupdate(m_sqlkey_event_updatecallstate, [$E.staff.epidSql, e.event_guid, e.callestablishtime, e.callestablishtime]
                        , 'async: true');
                }
            },

            //t: 1--insert, 2--update
            saveAgentCall: function(t) {
                var e = this.m_Event;
                var a = this.m_agentcall;
                    if (t == 2) {
                        $SC.executeupdate("softphone.agentcall.update.v201610"
                            , [$E.staff.epidSql, e.callstarttime, e.callendtime, e.callestablished, e.transferfrom, e.transferto
                                , a.value1, a.value2, a.value3, a.value4, a.value4, e.callbegintime, e.hangupType, e.event_guid, e.customer_guid, e.record_guid, a.failreason
                                , a.holdcount, a.holdduration, a.ringduration, a.talkduration
                                , a.subcallcount, a.subcallduration, a.subcallret, e.event_guid]
                            , 'async: true');
                    } else {
                        $SC.executeupdate("softphone.agentcall.insert.v201610"
                            , [$E.staff.epidSql, e.event_guid, a.connectionid, e.calltype, e.ani, e.dnis, e.callstarttime, e.callendtime, e.callestablished
                                , e.transferfrom, e.transferto, e.callbegintime, e.agentid, e.extension, e.hangupType
                                , e.handleby_id, e.event_guid, e.customer_guid, e.record_guid, a.failreason, e.handlegroup_id
                                , a.otherdn, a.thirdpartydn, a.holdcount, a.holdduration, a.ringduration, a. talkduration, a.subcallcount, a.subcallduration
                                , a.skillgroup, a.value1, a.value2, a.value3, a.value4, a.value5, a.firstrec_guid, a.prevrec_guid]
                            , 'async: true');
                }
            },

            __agentcall: function(evttime) {
                var dur = 0;
                var stime = undefined;
                if ($SC.CallInfo.CallState2 == 3) {
                    $SC.CallInfo.m_agentcall.m_holdtime = evttime;
                } else if ($SC.CallInfo.m_agentcall.m_holdtime) {
                    stime = $SC.CallInfo.m_agentcall.m_holdtime;
                    $SC.CallInfo.m_agentcall.m_holdtime = undefined;
                    if ($SC.CallInfo.CallState2 == 0 || $SC.CallInfo.CallState2 == 2) {
                        $SC.CallInfo.m_agentcall.holdcount++;
                        dur = new Date(evttime).getTime() - new Date(stime).getTime();
                        if (dur > 0) {
                            $SC.CallInfo.m_agentcall.holdduration+= dur/1000;
                        } else {
                            logmsg("SoftphoneCore--LOGWAR: " + "calc holdtime with unexpected start and endtime: " + stime + ", " + evttime);
                        }
                    }
                }

            },

            setEvent: function (callParas) {
                var t = this;
                if (t.m_Event && callParas) {
                    var props = callParas.split('|');
                    var signored = "";
                    for (let i = 0; i < props.length; i++) {
                        var oneprop = props[i].split('=');
                        if (oneprop.length > 1) {
                            switch (oneprop[0].toLowerCase()) {
                                case 'event_guid':
                                    if (t.m_Event.event_guid && oneprop[1] && t.m_Event.event_guid !=oneprop[1]) {
                                        losgmsg("setevent ignored for current event_guid = " + t.m_Event.event_guid);
                                        return;
                                    }
                                    break;
                                case 'workstarttime' :
                                case 'workendtime' :
                                case 'customer_guid' :
                                case 'customername' :
                                case 'comments' :
                                case 'stringfield2' :
                                case 'contact_customer_guid' :
                                case 'objectivestatus' :
                                case 'callresult_id' :
                                case 'callresultreason_id' :
                                case 'objective_guid':
                                case 'dynfield1':
                                case 'dynfield2':
                                case 'dynfield3':
                                case 'dynfield4':
                                case 'dynfield5':
                                    t.m_Event[oneprop[0].toLowerCase()] = oneprop[1];
                                    break;
                                default :
                                    if (!signored) {
                                        signored = signored + ", " + oneprop[0];
                                    } else {
                                        signored = "unsupported setEvent field " + oneprop[0];
                                    }
                                    //$SC.addconsolelog("unsupported setEvent field " + oneprop[0]);
                                    break;
                            }
                        }
                    }
                    if (!signored) {
                        $SC.addconsolelog(signored);
                    }
//logmsg("setevent", t.CallState2, t.m_Event, JSON.stringify(t.m_Event));
                    if (t.CallState2 == 0) {
                        t.saveEvent(2);
                    }
                }
            },

            getEvent: function (propname) {
                if (this.m_Event) {
                    if (!propname) {
                        return this.m_Event.event_guid;
                    } else {
                        return this.m_Event[propname];
                    }
                }
            },

            afterWorkEnd: function (workType) {
                if (!workType) {
                    if (this.m_Event) {
                        if (this.m_Event.calltype == '2') {
                            workType = 'WT-OB';
                        } else {
                            workType = 'WT-IB';
                        }
                    } else {
                        workType = m_tmp_worktype;
                    }
                }
                m_tmp_worktype = '';
                if ($SC.CallInfo.CallState2 == 0 && m_delayagentstate == 'notready') {
                    logmsg('SoftphoneCore -- delayed agentNotReady');
                    if (m_delayreasoncode) {
                        $SC.agentNotReady2(m_delayagentmode, m_delayreasoncode);
                    } else {
                        $SC.agentNotReady(m_delayagentmode);
                    }
                    m_delayagentstate = '';
                    m_delayagentmode = '';
                    m_delayreasoncode = '';
                    return;
                }
                if (workType == 'WT-OB') {
                    if (m_conf.m_OBReleaseState.toLowerCase() === 'ready') {
                        $SC.agentReady(2);
                    } else if (m_conf.m_OBReleaseState.toLowerCase() === 'notready') {
                        $SC.agentNotReady(3);
                    }
                } else {
                    if (m_conf.m_IBReleaseState.toLowerCase() === 'ready') {
                        $SC.agentReady(2);
                    } else if (m_conf.m_IBReleaseState.toLowerCase() === 'notready') {
                        $SC.agentNotReady(3);
                    }
                }
            },

            onCallEnd: function (call) {
                var t = this;

                var m_state = "";
                var m_reasoncode = '';

                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
                    if (t.m_Event.callestablished != 1 && m_conf.m_OBCallAbandonState) {
                        m_state = m_conf.m_OBCallAbandonState.toLowerCase();
                        m_reasoncode = m_conf.m_OBCallAbandonState;
                    } else {
                        m_state = m_conf.m_OBCallEndState.toLowerCase();
                        m_reasoncode = m_conf.m_OBCallEndReasonCode;
                    }
                    /*
                    if (m_conf.m_OBCallEndState.toLowerCase() === 'notready') {
                        if (m_conf.m_OBCallEndReasonCode) {
                            $SC.agentNotReady2(3, m_conf.m_OBCallEndReasonCode);
                        } else {
                            $SC.agentNotReady(3);
                        }
                    } else if (m_conf.m_OBCallEndState.toLowerCase() === 'acw') {
                        $SC.acw();
                    }
                     */
                } else {
                    if (t.m_Event.callestablished != 1 && m_conf.m_IBCallAbandonState) {
                        m_state = m_conf.m_IBCallAbandonState.toLowerCase();
                        m_reasoncode = m_conf.m_IBCallAbandonState;
                        /*
                        if (m_conf.m_IBCallAbandonState.toLowerCase() === 'notready') {
                            if (m_conf.m_IBCallAbandonReasonCode) {
                                $SC.agentNotReady2(3, m_conf.m_IBCallAbandonReasonCode, {nodelay: 1});
                            } else {
                                $SC.agentNotReady(3, {nodelay: 1});
                            }
                        } else if (m_conf.m_IBCallAbandonState.toLowerCase() === 'acw') {
                            $SC.acw();
                        }
                         */
                    } else {
                        m_state = m_conf.m_IBCallEndState.toLowerCase();
                        m_reasoncode = m_conf.m_IBCallEndReasonCode;
                        /*
                        if (m_conf.m_IBCallEndState.toLowerCase() === 'notready') {
                            if (m_conf.m_IBCallEndReasonCode) {
                                $SC.agentNotReady2(3, m_conf.m_IBCallEndReasonCode, {nodelay: 1});
                            } else {
                                $SC.agentNotReady(3, {nodelay: 1});
                            }
                        } else if (m_conf.m_IBCallEndState.toLowerCase() === 'acw') {
                            $SC.acw();
                        }
                         */
                    }
                }
                if (!m_worktype && m_delayagentstate == 'notready') {
                    m_state = "notready";
                    m_reasoncode = "";
                    if (m_tmp_worktype) {
                        logmsg('SoftphoneCore -- delayed agentNotReady wait afterWorkend');
                    } else {
                        logmsg('SoftphoneCore -- delayed agentNotReady');
                        m_reasoncode = m_delayreasoncode;
                        /*
                        if (m_delayreasoncode) {
                            $SC.agentNotReady2(m_delayagentmode, m_delayreasoncode);
                        } else {
                            $SC.agentNotReady(m_delayagentmode);
                        }
                         */
                        m_delayagentstate = '';
                        m_delayagentmode = '';
                        m_delayreasoncode = ';'
                    }
                }

                if (m_state) {
                    setTimeout(function() {
                        if (m_state === "notready") {
                            if (m_reasoncode) {
                                $SC.agentNotReady2(3, m_reasoncode, {nodelay: 1});
                            } else {
                                $SC.agentNotReady(3, {nodelay: 1});
                            }
                        } else if (m_state === "ready") {
                            $SC.agentReady(2, {nodelay: 1});
                        } else if (m_state === "acw") {
                            $SC.acw();
                        }
                    }, 100);
                }

                var bAutoWorkEnd = false;
                var tAutoWorkEnd = 0;
                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
                    if (m_conf.m_AutoWorkEndForOutbound == 1) {
                        bAutoWorkEnd = true;
                        tAutoWorkEnd = m_conf.m_AutoWorkEndDelayForOutbound;
                    }
                }
                if (t.CallType == $CTI_CONST.CALL_TYPE.CT_INBOUND) {
                    if (m_conf.m_AutoWorkEndForInbound == 1) {
                        bAutoWorkEnd = true;
                        tAutoWorkEnd = m_conf.m_AutoWorkEndDelayForInbound;
                    }
                }
                if (t._timer_autoworkend) {
                    clearTimeout(t._timer_autoworkend);
                    t._timer_autoworkend = 0;
                }
                if (bAutoWorkEnd) {
                    t._timer_autoworkend = setTimeout(function() {
                        t._timer_autoworkend = 0;
                        logmsg("SoftphoneCore -- Auto WorkEnd");
                        $SC.notifyWorkEnd();
                    }, tAutoWorkEnd);
                }
            }
        };

        function SoftphoneCore() {
            var sc = this;

            //sc.cticlient=ELITEWSCTIClient;
            sc.config = _iniconfig;	// {};
            sc.ctiType = '';
            sc.severEndpoint = '';
            //sc.dn = $.cookie("jssoftphone.extension");
            sc.dn = localStorage.getItem("jssoftphone.extension")
            sc.extension = this.dn;
            //sc.agentId = $.cookie("jssoftphone.agentid");
            sc.agentId = localStorage.getItem("jssoftphone.agentid");
            sc.agentPassword = '';
            sc.agentGroup = '';
            //sc.queue = $.cookie("jssoftphone.queue");
            sc.queue = localStorage.getItem("jssoftphone.queue");
            sc.position = '';
            sc.acdAgent = 1;	//1 使用avaya的ACD工号, 2 使用AvayaTSAPIProxy的虚拟工号, 只有支持虚拟工号的平台需要此参数

            sc.agentState = -1;
            sc.agentMode = $CTI_CONST.AGENT_WORKMODE.AUX;
            sc.reasonCode = 0;

            sc.AgentState = this.agentState;
            sc.EvtDetail = '';

            sc.m_logagentdetail = false;
            sc.m_agent_status_detail_guid = '';
            sc.m_agent_status_detail_starttime = undefined;

            sc.m_loglogindetail = false;
            sc.agent_login_guid = '';
            sc.logintime = undefined;
            sc.logouttime = undefined;

            sc.Recording_GUID = '';
            sc.Recording_File = '';
            sc.RecordingFlag = 0;

            //sc.autoAnswer = false;
            sc.autoPrefix = '';

            sc.TransferOnDialingHold = m_conf.m_transferondialinghold;

            sc.cache = {
                config: {
                    ctiType: {},
                    agentRolegroup: {},
                    extension: {}
                }
            };

            sc.CallInfo = new CallInfos();
            sc.CallStat = new CallStats();

            sc.Agent_Status_Detail = {
                StartTime: undefined,

                m_time: undefined,
                m_agentstatechanged: false
            };

            sc.LoginInfo = {
                agent_login_guid: '',
                logintime: undefined,
                logouttime: undefined,
                logined: false
            };

            sc.AgentStatusInfo = {};
            sc.loginCallback = undefined;
        }

        SoftphoneCore.prototype = {

            /**
             * 可用的evtName: OnSCTIEvent/OnCTIEvent
             * callerName: 自行约定。
             * index: 一般为0，ctiextra模块传入-1。
             */
            addEvtListener: function (callerName, evtName, evt, index, params) {
                //debugger;

                if (params && params.inittime && m_inittime != params.inittime) {
                    logmsg("SoftphoneCore.addEvtListner ignored, for invalid inittime " + params.inittime, callerName, evtName);
                    return false;
                }

                if (!index || isNaN(index)) {
                    index = 0;
                } else {
                    index = parseInt(index);
                }

                if (evtName == 'OnSCTIEvent') {
                    var bfound = false;
                    for (var i = 0; i < m_OnSCTIEventListener.length; i++) {
                        if (m_OnSCTIEventListener[i].callerName == callerName) {
                            bfound = true;
                            break;
                        }
                    }
                    if (!bfound) {
                        m_OnSCTIEventListener.push({
                            "index": index,
                            "callerName": callerName,
                            "evtName": evtName,
                            "evt": evt
                        });
                        logmsg('SoftphoneCore -- addEvtListener: callerName = ' + callerName + ', evtName = ' + evtName + ', count = ' + m_OnSCTIEventListener.length);
                        m_OnSCTIEventListener.sort(function (a, b) {
                            return a.index - b.index;
                        })
                    }
                } else if (evtName == 'OnOrigCTIEvent') {
                    var bfound = false;
                    for (var i = 0; i < m_OnCTIEventListener.length; i++) {
                        if (m_OnCTIEventListener[i].callerName == callerName) {
                            bfound = true;
                            break;
                        }
                    }
                    if (!bfound) {
                        m_OnCTIEventListener.push({
                            "index": index,
                            "callerName": callerName,
                            "evtName": evtName,
                            "evt": evt
                        });
                        logmsg('SoftphoneCore -- addEvtListener: callerName = ' + callerName + ', evtName = ' + evtName);
                        m_OnCTIEventListener.sort(function (a, b) {
                            return a.index - b.index;
                        })
                    }
                }
            },

            //callnames = [['callname1',callbackfunc1],['callname2',callbackfunc2]]
            regcall: function (callername, callnames) {
                m_regcalls[callername.toLowerCase()] = callnames;
            },

            //softphone.agent_current_state=select agentid from agent_current_state where agentid=@{C1}S
            //softphone.agent_current_state.insert=insert into agent_current_state(agentid,statetime,status,workmode,devicedn,queue,connectionid,callrelated,caltype,ani,dnis,vdn,reasoncode) values(@{C1}S,@{C2}D,@{C3}N,@{C4}N,@{C5}S,@{C6}S,@{C7}S,@{C8}N,@{C9}N,@{C10}S,@{C11}S,@{C12}S,@{C13}N)
            //softphone.agent_current_state.update=update agent_current_state set statetime=@{C2}D,status=@{C3}N,workmode=@{C4}N,devicedn=@{C5}S,queue=@{C6}S,connectionid=@{C7}S,callrelated=@{C8}N,calltype=@{C9}N,ani=@{C10}S,dnis=@{C11}S,vdn=@{C12}S,reasoncode=@{C13}N where agentid=@{C1}S
            //t: 1--insert, 2--update
            saveagentcurrentstate: function (t) {
                if (t == 1) {
                    this.executeupdate("softphone.agent_current_state.insert", [m_agent_stat.agentid, m_agent_stat.statetime, m_agent_stat.agentstate, m_agent_stat.workmode, m_agent_stat.devicedn, m_agent_stat.queue, m_agent_stat.connectionid, m_agent_stat.callrelated, m_agent_stat.calltype, m_agent_stat.ani, m_agent_stat.dnis, m_agent_stat.vdn, m_agent_stat.reasoncode], true)
                } else {
                    this.executeupdate("softphone.agent_current_state.update", [m_agent_stat.agentid, m_agent_stat.statetime, m_agent_stat.agentstate, m_agent_stat.workmode, m_agent_stat.devicedn, m_agent_stat.queue, m_agent_stat.connectionid, m_agent_stat.callrelated, m_agent_stat.calltype, m_agent_stat.ani, m_agent_stat.dnis, m_agent_stat.vdn, m_agent_stat.reasoncode], true)
                }
            },

            //softphone.sta_agent_today=select startdate,staff_id,agentid,logintime,readytime,maxreadytime,auxtime,maxauxtime,totalib,totalibtalk,totalibtime,totalibtalktime,maxibtalktime,totalibacwtime,maxibacwtime,totalob,totalobtalk,totalobtime,totalobtalktime,maxobtalktime,totalobacwtime,maxobacwtime,reason1count,reason1time,reason2count,reason2time,reason3count,reason3time,reason4count,reason4time,reason5count,reason5time,reason6count,reason6time,reason7count,reason7time,reason8count,reason8time,reason9count,reason9time,reasonallcount,reasonalltime from sta_agent_today where staff_id='{C_BY}'
            //softphone.sta_agent_today.delete=delete from sta_agent_today where staff_id='{C_BY}'
            //softphone.sta_agent_today.insert=insert into sta_agent_today(startdate,staff_id,agentid,logintime,readytime,maxreadytime,auxtime,maxauxtime,totalib,totalibtalk,totalibtime,totalibtalktime,maxibtalktime,totalibacwtime,maxibacwtime,totalob,totalobtalk,totalobtime,totalobtalktime,maxobtalktime,totalobacwtime,maxobacwtime,reason1count,reason1time,reason2count,reason2time,reason3count,reason3time,reason4count,reason4time,reason5count,reason5time,reason6count,reason6time,reason7count,reason7time,reason8count,reason8time,reason9count,reason9time,reasonallcount,reasonalltime) values(@{C1}D,'{C_BY}',@{C3}S,@{C4}D,@{C5}N,@{C6}N,@{C7}N,@{C8}N,@{C9}N,@{C10}N,@{C11}N,@{C12}N,@{C13}N,@{C14}N,@{C15}N,@{C16}N,@{C17}N,@{C18}N,@{C19}N,@{C20}N,@{C21}N,@{C22}N,@{C23}N,@{C24}N,@{C25}N,@{C26}N,@{C27}N,@{C28}N,@{C29}N,@{C30}N,@{C31}N,@{C32}N,@{C33}N,@{C34}N,@{C35}N,@{C36}N,@{C37}N,@{C38}N,@{C39}N,@{40}N,@{C41}N,@{42}N)
            //softphone.sta_agent_today.update=update sta_agent_today set startdate=@{C1}D,agentid=@{C3}S,logintime=@{C4}D,readytime=@{C5}N,maxyreadytime=@{C6}N,auxtime=@{C7}N,maxauxtime=@{C8}N,totalib=@{C9}N,totalibtalk=@{C10}N,totalibtime=@{C11}N,totalibtalktime=@{C12}N,maxibtalktime=@{C13}N,totalibacwtime=@{C14}N,maxibacwtime=@{C15}N,totalo=@{C16}N,totalobtalk=@{C17}N,totalobtime=@{C18}N,totalobtalktime=@{C19}N,maxobtalktime=@{C20}N,totalobacwtime=@{C21}N,maxobacwtime=@{C22}N,reaon1count=@{C23}N,reason1time=@{C24}N,reason2count=@{C25}N,reason2time=@{C26}N,reason3count=@{C27}N,reason3time=@{C28}N,reason4count=@{C29}N,reason4time=@{C30}N,reason5count=@{C31}N,reason5time=@{C32}N,reason6count=@{C33}N,reason6time=@{C34}N,reason7count=@{C35}N,reason7time=@{C36}N,reason8count=@{C37}N,reason8time=@{C38}N,reason9count=@{C39}N,reason9time=@{40}N,reasonallcount=@{C41}N,reasonalltime=@{42}N where staff_id='{C_BY}'
            savestaagenttoday: function (t) {
                if (t == 1) {
                    this.executeupdate("softphone.sta_agent_today.insert", [m_agent_stat.statetime, $E.staff.id, m_agent_stat.agentid, m_agent_stat.logintime, m_agent_stat.readytime, m_agent_stat.maxreadytime, m_agent_stat.auxtime, m_agent_stat.maxauxtime, m_agent_stat.totalib, m_agent_stat.totalibtalk, m_agent_stat.totalibtime, m_agent_stat.totalibtalktime, m_agent_stat.maxibtalktime, m_agent_stat.totalibacwtime, m_agent_stat.maxibacwtime, m_agent_stat.totalob, m_agent_stat.totalobtalk, m_agent_stat.totalobtime, m_agent_stat.totalobtalktime, m_agent_stat.maxobtalktime, m_agent_stat.totalobacwtime, m_agent_stat.maxobacwtime, m_agent_stat.reason1count, m_agent_stat.reason1time, m_agent_stat.reason2count, m_agent_stat.reason2time, m_agent_stat.reason3count, m_agent_stat.reason3time, m_agent_stat.reason4count, m_agent_stat.reason4time, m_agent_stat.reason5count, m_agent_stat.reason5time, m_agent_stat.reason6count, m_agent_stat.reason6time, m_agent_stat.reason7count, m_agent_stat.reason7time, m_agent_stat.reason8count, m_agent_stat.reason8time, m_agent_stat.reason9count, m_agent_stat.reason9time, m_agent_stat.reasonallcount, m_agent_stat.reasonalltime], true)
                } else {
                    this.executeupdate("softphone.sta_agent_today.update", [m_agent_stat.statetime, $E.staff.id, m_agent_stat.agentid, m_agent_stat.logintime, m_agent_stat.readytime, m_agent_stat.maxreadytime, m_agent_stat.auxtime, m_agent_stat.maxauxtime, m_agent_stat.totalib, m_agent_stat.totalibtalk, m_agent_stat.totalibtime, m_agent_stat.totalibtalktime, m_agent_stat.maxibtalktime, m_agent_stat.totalibacwtime, m_agent_stat.maxibacwtime, m_agent_stat.totalob, m_agent_stat.totalobtalk, m_agent_stat.totalobtime, m_agent_stat.totalobtalktime, m_agent_stat.maxobtalktime, m_agent_stat.totalobacwtime, m_agent_stat.maxobacwtime, m_agent_stat.reason1count, m_agent_stat.reason1time, m_agent_stat.reason2count, m_agent_stat.reason2time, m_agent_stat.reason3count, m_agent_stat.reason3time, m_agent_stat.reason4count, m_agent_stat.reason4time, m_agent_stat.reason5count, m_agent_stat.reason5time, m_agent_stat.reason6count, m_agent_stat.reason6time, m_agent_stat.reason7count, m_agent_stat.reason7time, m_agent_stat.reason8count, m_agent_stat.reason8time, m_agent_stat.reason9count, m_agent_stat.reason9time, m_agent_stat.reasonallcount, m_agent_stat.reasonalltime], true)
                }
            },

            querycall: function (callname, params, callback) {
                try {
                    for (let v in m_regcalls) {
                        for (let i = 0; i < m_regcalls[v].length; i++) {
                            if (m_regcalls[v][i][0].toLowerCase() == callname) {
                                m_regcalls[v][i][1](callname, params, function (backparams) {
                                    if ($.isFunction(callback)) {
                                        callback(backparams);
                                    }
                                });
                            }
                        }
                    }
                } catch (e) {

                }
            },

            fireSCTIEvent: function (evt, datas, evttime, onlyfire) {
                if (!onlyfire) {
                    if (evt.toLowerCase() == 'callstatechange' || evt.toLowerCase().substr(0, 6) == 'oncall') {
                        this.dumpcalllist(evt)
                    }

                    if (evt === "callstatechange") {
                        $SC.CallInfo.__agentcall(evttime);
                    }

                    if (evt == 'callstatechange' || evt == $CTI_CONST.CTI_MSG.EVT_RINGING) {
                        this.onagentstate(datas, evt, evttime);
                    }

                    if ($SC.CallInfo.monitorcall && $SC._callback_monitor) {
                        if (evt == "OnCallEstablish") {
                            $SC.endmonitorcallback({"code": 0, "reason": "success"});
                        }
                        if (evt == "OnCallEnd") {
                            $SC.endmonitorcallback({"code": 0, "reason": "success"});
                        }
                    }
                }

                logmsg('SoftphoneCore -- FireSCTIEvent(' + evt + '), CallState2 = ' + $SC.CallInfo.CallState2 + ', AgentState = ' + $SC.agentState + ", agentMode = " + $SC.agentMode);
                try {
                    for (var i = 0; i < m_OnSCTIEventListener.length; i++) {
                        if ($SC.CallInfo.monitorcall && (evt == "OnCallStart" || evt == "OnCallEstablish" || evt == "OnCallEnd") && m_OnSCTIEventListener[i].callerName === "softphone.api") {
                            //this.addlog('SoftphoneCore - fireSCTIEvent', 'monitorcall = ' + $SC.CallInfo.monitorcall + ', FireSCTIEvent OnCallAction to ' + m_OnSCTIEventListener[i].callerName, undefined, 'fireSCTIEvent');
                            logmsg('fireSCTIEvent', 'monitorcall = ' + $SC.CallInfo.monitorcall + ', FireSCTIEvent OnCallAction to ' + m_OnSCTIEventListener[i].callerName);
                            m_OnSCTIEventListener[i].evt("OnCallAction,monitor_" + $SC.CallInfo.monitorcall + "_" + evt);
                            break;
                        }
                        //this.addlog('SoftphoneCore - fireSCTIEvent', 'FireSCTIEvent to ' + m_OnSCTIEventListener[i].callerName + ', ' + evt, undefined, 'fireSCTIEvent');
                        logmsg('fireSCTIEvent', 'FireSCTIEvent to ' + m_OnSCTIEventListener[i].callerName + ', ' + evt);
                        m_OnSCTIEventListener[i].evt(evt);
                    }
                } catch (e) {

                }
                //this.addlog('SoftphoneCore - fireSCTIEvent', 'FireSCTIEvent done, ' + evt, undefined, 'fireSCTIEvent');
                logmsg('fireSCTIEvent', 'FireSCTIEvent done, ' + evt);
            },

            fireCTIEvent: function (datas) {
                var evtd = '';
                var evt1 = '';
                if (datas) {
                    for (let a in datas) {
                        if (datas[a].type == 5) {
                            if (!evt1 || a.toLowerCase() == 'userdata') {
                                evt1 = '';
                                var datas1 = datas[a].value;
                                for (let a1 in datas1) {
                                    evt1 = evt1 + '|' + a1 + '=' + datas1[a1].value;
                                }
                            }
                        } else {
                            evtd = evtd + '|' + a + '=' + datas[a].value;
                        }
                    }
                }
                if (evtd) {
                    evtd = evtd.substring(1);
                    if (evt1) {
                        evtd = evtd.substring(1) + '#' + evt1.substring(1);
                    }
                }
                this.EvtDetail = evtd;
                try {
                    for (var i = 0; i < m_OnCTIEventListener.length; i++) {
                        //this.addlog('SoftphoneCore - fireCTIEvent', 'FireCTIEvent to ' + m_OnCTIEventListener[i].callerName + ', ' + datas.event.value, undefined, 'fireCTIEvent');
                        logmsg('fireCTIEvent', 'FireCTIEvent to ' + m_OnCTIEventListener[i].callerName + ', ' + datas.event.value);
                        m_OnCTIEventListener[i].evt(datas);
                    }
                } catch (e) {

                }
                //this.addlog('SoftphoneCore - fireCTIEvent', 'FireCTIEvent done', undefined, 'fireCTIEvent')
                logmsg('fireCTIEvent', 'FireCTIEvent done')
            },

            //addlog: function (c, msg, obj, consoleLogType) {
                /*
                try {
                    $F.log(c, msg, obj);
                    var _phone_console_ = 'onSendMessage|onCTIEvent|executeupdatesql|cticall';
                    if (_phone_console_.indexOf(consoleLogType) >= 0) {
                        //console.info(new Date().toLocaleTimeString() + ' ' + msg);
                        $SC.addconsolelog(msg);
                    }
                } catch (e) {
                }
                 */
            //},

            dumpcalllist: function (sfor) {
                var calls = '';
                var tstate1 = 0, tstate = 0;
                //if (sfor == 'callstatechange') {
                for (let x in $SC.CallInfo.m_Calllist) {
                    tstate1 = $SC.CallInfo.m_Calllist[x].callstate;
                    switch (tstate1) {
                        case $CTI_CONST.CALL_STATE.CS_RINGING:
                            tstate = tstate | 1;
                            break;
                        case $CTI_CONST.CALL_STATE.CS_TALKING:
                            tstate = tstate | 2;
                            break;
                        case $CTI_CONST.CALL_STATE.CS_HELD:
                            tstate = tstate | 4;
                            break;
                        case $CTI_CONST.CALL_STATE.CS_DIALING:
                            tstate = tstate | 8;
                            break;
                    }
                    calls = calls + '(' + x + ',' + $SC.CallInfo.m_Calllist[x].anotherconn + ',' + $SC.CallInfo.m_Calllist[x].callstate + ')'
                }
                switch (tstate) {
                    case 1:
                        tstate = $CTI_CONST.CALL_STATE.CS_RINGING;
                        break;
                    case 2:
                        tstate = $CTI_CONST.CALL_STATE.CS_TALKING;
                        break;
                    case 4:
                        tstate = $CTI_CONST.CALL_STATE.CS_HELD;
                        break;
                    case 8:
                        tstate = $CTI_CONST.CALL_STATE.CS_DIALING;
                        break;
                    case 2 | 4:
                        tstate = $CTI_CONST.CALL_STATE.CS_TALKINGHELD;
                        break;
                    case 4 | 8:
                        tstate = $CTI_CONST.CALL_STATE.CS_DIALINGHELD;
                        break;
                    default:
                        tstate = -tstate;
                }
                if (sfor) {
                    if (tstate > 0 && $SC.CallInfo.CallState2 != tstate) {
                        logmsg('::SoftphoneCore -- CallState2 = ' + $SC.CallInfo.CallState2 + '?');
                        $SC.CallInfo.CallState2 = tstate;
                    }
                    logmsg('::SoftphoneCore -- ' + sfor + calls + ', CallState2 = ' + $SC.CallInfo.CallState2 + ', activeParties = ' + $SC.CallInfo.CallParty.activeParties);
                }
                //}
                return calls;
            },

            get autoAnswer() {
                if (m_conf.m_AutoAnswer == 1) {
                    return true;
                } else {
                    return false;
                }
            },

            set autoAnswer(value) {
                if (value) {
                    m_conf.m_AutoAnswer = 1;
                } else {
                    m_conf.m_AutoAnswer = -1;
                }
            },

            get scpath() {
                return scpath;
            },

            get sccrossorigin() {
                return sccrossorigin;
            },

            get scfileext() {
                return scfileext;
            },
            ,
            /*
             * 软电话初始化，包括读取ini
             */
            initSoftphone: function (succFunc, failFunc, params) {
                var t = this;
                var resetctitype = false;
                m_inittime = new Date().valueOf();
                if (params) {
                    logmsg("softphone.core.initsoftphone with params", m_inittime,JSON.stringify(params));
                    ctitype = params.ctiType;
                    t.ctiType = ctitype;
                } else {
                    logmsg("softphone.core.initsoftphone", m_inittime);
                }
                if (!ctitype) {
                    ctitype = $SC._getconfig("cti", "ctitype");
                    if (ctitype) {
                        logmsg("initSoftphone, default ctitype " + ctitype);
                        t.ctiType = ctitype;
                    }
                }

                m_softphonestep = 0;
                if (m_softphonestep == 0) {
                    //remove prev initsoftphone loaded ctiextras, cticlient, and cti iframe
                    try {
                        var cti = document.getElementById("cti");
                        if (cti) {
                            cti.parentNode.removeChild(cti);
                        }
                        if (t.ctiextras || t.cticlient) {
                            var allscript = document.getElementsByTagName("script");
                            if (allscript) {
                                for (let i = allscript.length - 1; i >= 0; i--) {
                                    if (allscript[i] && ((t.ctiextras && t.ctiextras.length) || t.cticlient)) {
                                        var src = allscript[i].getAttribute("src");
                                        if (src) {
                                            if (t.cticlient && src.indexOf(t.cticlient) >= 0) {
                                                $("script[src=" + src + "]").remove();
                                                allscript[i].parentNode.removeChild(allscript[i]);
                                                t.cticlient = undefined;
                                            }
                                            for (let j = t.ctiextras.length - 1; j >= 0; j--) {
                                                if (src.indexOf(t.ctiextras[j]) >= 0) {
                                                    $("script[src=" + src + "]").remove();
                                                    allscript[i].parentNode.removeChild(allscript[i]);
                                                    t.ctiextras.splice(j, 1);
                                                }
                                            }
                                        }
                                    }
                                }
                            }
                        }
                        m_ctiextras = {};
                        t.ctiextras = undefined;
                        t.cticlient = undefined;
                        t.ctiextras = undefined;
                    } catch (e) {

                    }
                    cticlient = undefined;

                    var m_ctievt_softphoneapi;
                    var m_sctievt_softphoneapi;
                    if (params && params.resetctitype) {
                        resetctitype = true;
                        for (let i = 0; i < m_OnSCTIEventListener.length; i++) {
                            if (m_OnSCTIEventListener[i].callerName == "softphone.api") {
                                m_sctievt_softphoneapi = m_OnSCTIEventListener[i];
                                break;
                            }
                        }
                        for (let i = 0; i < m_OnCTIEventListener.length; i++) {
                            if (m_OnCTIEventListener[i].callerName == "softphone.api") {
                                m_ctievt_softphoneapi = m_OnCTIEventListener[i];
                                break;
                            }
                        }
                    }
                    m_OnSCTIEventListener = [];
                    m_OnCTIEventListener = [];
                    if (m_ctievt_softphoneapi) {
                        m_OnCTIEventListener.push({
                            "index": m_ctievt_softphoneapi.index,
                            "callerName": m_ctievt_softphoneapi.callerName,
                            "evtName": m_ctievt_softphoneapi.evtName,
                            "evt": m_ctievt_softphoneapi.evt
                        });
                    }
                    if (m_sctievt_softphoneapi) {
                        m_OnSCTIEventListener.push({
                            "index": m_sctievt_softphoneapi.index,
                            "callerName": m_sctievt_softphoneapi.callerName,
                            "evtName": m_sctievt_softphoneapi.evtName,
                            "evt": m_sctievt_softphoneapi.evt
                        });
                    }
                    m_softphonestep = 1;
                    setTimeout(function () {
                        if (m_softphonestep == 1) {
                            m_softphonestep = 3;
                            if ($.isFunction(failFunc)) {
                                setTimeout(function () {
                                    logmsg("SoftphoneCore -- initsoftphone callback failfunc on timeout");
                                    failFunc(false);
                                }, 100);
                            }
                        }
                    }, 180000);
                    //this.loadConfig(function(){
                    //debugger;

                    m_OBCheckPhoneNo = t.getParam('CHKPHO');
                    m_DBMASK = t.getParam('DBMASK');

                    if (m_DBMASK) {
                        m_masker_event_ani = '';
                        m_masker_event_dnis = '';
                        m_masker_record_ani = '';
                        m_masker_record_dnis = '';

                        var ret = $E.getActiveProject().commonQuerySync('ECore.Codetable.dbMasker', []);
                        if (ret && ret.value[0].count > 0) {
                            for (let i = 0; i < ret.value[0].count; i++) {
                                ret.value[0].fields[i][0] = ret.value[0].fields[i][0].toLowerCase();
                                ret.value[0].fields[i][1] = ret.value[0].fields[i][1].toLowerCase();
                            }
                            m_masker = $F.makeJsonArray(ret.value[0]);
                        } else {
                            m_masker = undefined;
                        }
                    }

                    logmsg('to _getini and to get cticlient, ctitype = ' + ctitype);
                    t._getini(true, $E.staff.agentId);
                    var jscticlient = t._getconfig('CTI', 'cticlient');

                    if (!jscticlient) {
                        //jscticlient = $E.softphoneBasePath + "/softphone/softphone.elitewscticlient" + $E.jsv;
                        jscticlient = scpath + "/softphone.elitewscticlient" + $E.jsv;
                    } else {
                        jscticlient = decodeURI(jscticlient);
                        if (jscticlient.indexOf('$') >= 0 || jscticlient.indexOf('+') >= 0) {
                            jscticlient = eval(jscticlient);
                        }
                    }
                    t.cticlient = jscticlient;

                    logmsg('SoftphoneCore -- require ' + jscticlient);
                    cticlient = undefined;
                    require([jscticlient], function (CTIClientFactory) {
                        logmsg('SoftphoneCore -- require ' + jscticlient + ' success');
                        if (CTIClientFactory.hasOwnProperty('getCTIClient')) {
                            //debugger;
                            CTIClientFactory.getCTIClient(function (realcticlient) {
                                //debugger;
                                logmsg("SoftphoneCore -- cticlient by getCTIClient");
                                cticlient = realcticlient;
                                if (!cticlient) {
                                    logmsg('SoftphoneCore -- cticlient got ' + cticlient);
                                }
                                if ($.isFunction(succFunc)) {
                                    setTimeout(function () {
                                        logmsg("SoftphoneCore -- initsoftphone callback succfunc on getCTIClient");
                                        succFunc(true);
                                    }, 100);
                                }
                                m_softphonestep = 2;
                                m_evtbak = $SC.getParam('EVTBAK');
                                if (m_evtbak) {
                                    m_evtbak = m_evtbak.toLowerCase();
                                }
                            })
                        } else {
                            //debugger;
                            cticlient = CTIClientFactory;
                            logmsg("SoftphoneCore -- cticlient direct");
                            if (!cticlient) {
                                logmsg('SoftphoneCore -- cticlient got ' + cticlient);
                            }
                            if ($.isFunction(succFunc)) {
                                setTimeout(function () {
                                    logmsg("SoftphoneCore -- initsoftphone callback succfunc on cticlient direct");
                                    succFunc(true);
                                }, 100);
                            }
                            m_softphonestep = 2;
                            m_evtbak = $SC.getParam('EVTBAK');
                            if (m_evtbak) {
                                m_evtbak = m_evtbak.toLowerCase();
                            }
                        }
                    }, function (err) {
                        logmsg('SoftphoneCore -- require ' + jscticlient + ' fail with err ' + JSON.stringify(err));
                        m_softphonestep = 3;
                        if ($.isFunction(failFunc)) {
                            setTimeout(function () {
                                logmsg("SoftphoneCore -- initsoftphone callback failfunc on require jsclient error");
                                failFunc(false);
                            }, 100);
                        }
                    });
                    //}, function(){
                    //	m_softphonestep = 3;
                    //	if($.isFunction(failFunc)){
                    //		failFunc();
                    //    }
                    //});
                } else if (m_softphonestep == 3) {
                    if ($.isFunction(failFunc)) {
                        logmsg("SoftphoneCore -- initsoftphone callback succfunc softphonestep == 3");
                        failFunc(false);
                    }
                } /* else if (m_softphonestep > 1) {
                	if($.isFunction(succFunc)){
                		succFunc();
                    }
            	} */
                logmsg("softphone.core.initsoftphone done");
            },

            /**
             * CTIEvent handler
             * @param evt
             */
            onCTIEvent: function (evt, callingobj) {
                var datas;
                if (typeof (evt) == 'string') {
                    datas = evt;
                } else if (evt.data2) {
                    datas = evt.data2;
                } else if (evt.data) {
                    datas = evt.data;
                } else {
                    datas = evt;
                }
                logmsg("onCTIEvent", datas);
                if (typeof (datas) == 'string') {
                    var datas = JSON.parse(datas);
                }

                var breleased = false;
                var bcall = false;
                switch (parseInt(datas.event.value)) {
                    case $CTI_CONST.CTI_MSG.EVT_LINKCONNCTED:	//12
                        m_softphonestep = 12;
                        this.onLinkConnected(datas);
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_LINKDISCONNECTED:	//13
                        //break;
                    case $CTI_CONST.CTI_MSG.EVT_SERVERDISCONNECTED:	//15
                        this.onagentstate(datas);
                        m_softphonestep = 2;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_REGISTERED:		//16
                        m_softphonestep = 22;
                        this.onRegistered(datas);
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_UNREGISTERED:	//17
                        m_softphonestep = 12;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_AGENTLOGIN:		//70
                        if (datas.platinfo) {
                            var pinfo0 = datas.platinfo.value;
                            var pinfo = {};
                            for (let v in pinfo0) {
                                pinfo[v] = pinfo0[v].value;
                            }
                            $SC.platinfo = pinfo;
                        }
                    case $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT:	//71
                    case $CTI_CONST.CTI_MSG.EVT_AGENTNOTREADY:	//72
                    case $CTI_CONST.CTI_MSG.EVT_AGENTREADY:		//73
                        this.onagentstate(datas);
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_PARTYCHANGED:	//22
                        //tbd20190614

                        if (datas.userdata && datas.userdata.value && datas.userdata.value.ucid) {
                            var ucidp = datas.userdata.value.ucid.value;
                            if (ucidp) {
                                logmsg("UCIDP changed to " + ucidp + ", from " + $SC.CallInfo.m_UCIDP);
                                $SC.CallInfo.m_UCIDP = ucidp;
                                if ($SC.CallInfo.m_UCIDs.indexOf(ucidp) < 0) {
                                    $SC.CallInfo.m_UCIDs = $SC.CallInfo.m_UCIDs + '|' + ucidp;
                                }
                                $SC.CallInfo.m_userdatas.ucid = datas.userdata.value.ucid;
                            }
                        }

                        this.CallInfo.changeCall(datas);
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_RELEASED:		//3
                        breleased = true;
                        this.CallInfo.removeCall(datas);
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_RINGING:		//1

                    case $CTI_CONST.CTI_MSG.EVT_DIALING:		//20
                    case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:		//2
                    case 52:									//EVT_TREATMENTAPPLIED=52;
                    case $CTI_CONST.CTI_MSG.EVT_HELD:			//6
                    case $CTI_CONST.CTI_MSG.EVT_RETRIEVED:		//7
                    case $CTI_CONST.CTI_MSG.EVT_PARTYDELETED:	//9
                    case 53:									//EVT_TREATMENTEND=53;
                    case $CTI_CONST.CTI_MSG.EVT_CONFERENCED:	//21
                    case $CTI_CONST.CTI_MSG.EVT_RINGBACK:       //39
                        bcall = true;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_RECORDSTARTED:
                        if (m_conf.m_reportdelayflag) {
                            m_conf.m_reportdelayflag = false;
                            $SC.toReportAgent();
                        }
                    case $CTI_CONST.CTI_MSG.EVT_ERROR:
                        if (this.loginCallback && this.result) {
                            this.result.code = 'R_FAIL';
                            this.result.message = 'Login failed by CTI EVT_ERROR';
                            this.result.err = datas;
                            this.loginCallback.incallback = true;
                            var ret = {};
                            ret.code = this.result.code;
                            ret.type = "evt_error";
                            if (datas.errordesc || datas.errorcode) {
                                if (datas.errorcode) {
                                    ret.errorcode = datas.errorcode.value;
                                }
                                if (datas.errordesc) {
                                    ret.errordesc = datas.errordesc.value;
                                } else {
                                    ret.errordesc = ret.errorcode;
                                }
                            }
                            logmsg("loginCallback", false, ret);
                            this.loginCallback.callback(this.result.code == 'R_OK', ret);
                            this.loginCallback = undefined;
                            if (!$E.softphone) {
                                var er = datas.errordesc;
                                if (!er) {
                                    er = $SC.lang("common.msg.loginfail", "登录失败");
                                    if (datas.errorcode) {
                                        if (datas.errorcode.value) {
                                            //er = er + '，错误代码：' + datas.errorcode.value;
                                            er = $SC.lang("common.msg.loginfailplus", "登录失败，" + "错误代码：" + datas.errorcode.value);
                                        }
                                    }
                                } else {
                                    if (er.value) {
                                        er = $SC.lang("common.msg.loginfailplus", "登录失败，") + er.value;
                                    } else {
                                        er = $SC.lang("common.msg.loginfailplus", "登录失败，") + er;
                                    }
                                }
                                if (er) {
                                    $F.alert(er);
                                }
                            }
                        }
                        break;
                    default :
                        break;
                }
                if (bcall) {
                    if (!breleased && !this.CallInfo.CallState2) {
                        this.CallInfo = new CallInfos();
                    }
                    if (evt.monitorcall) {
                        this.CallInfo.monitorcall = evt.monitorcall.value;
                    }
                    if (this.CallInfo.addCall(datas) == -1) {
                        return;
                    }
                } else if (parseInt(datas.event.value) == $CTI_CONST.CTI_MSG.EVT_DATAUPDATED) {
                    if (datas.monitorcall) {
                        this.CallInfo.monitorcall = datas.monitorcall.value;
                        $SC.endmonitorcallback({"code": 0, "reason": "success"});
                    }
                    /*
                    if (evt.monitorcall) {
                        this.CallInfo.monitorcall = evt.monitorcall.value;
                        $SC.endmonitorcallback({"code": 0, "reason": "success"});
                    }
                     */
                    logmsg('[testtest] CallInfo.addCall to process EVT_DATAUPDATED');
                    if (this.CallInfo.addCall(datas) == -1) {
                        return;
                    }
                }

                //临时处理版本：2021/04/30
                switch (parseInt(datas.event.value)) {
                    case $CTI_CONST.CTI_MSG.EVT_RINGING:
                        $SC.CallInfo.CallParty.activeParties = 2;
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_DIALING:
                        if ($SC.CallInfo.CallParty.activeParties) {
                            $SC.CallInfo.CallParty.activeParties++;
                        } else {
                            $SC.CallInfo.CallParty.activeParties = 2;
                        }
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_ESTABLISH:
                        if (!$SC.CallInfo.CallParty.activeParties) {
                            $SC.CallInfo.CallParty.activeParties = 2;
                        }
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_PARTYADDED:
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_PARTYDELETED:
                        if ($SC.CallInfo.CallParty.activeParties > 2) {
                            var smsg = $SC.lang("common.msg.partydeleted", "");
                            if (smsg) {
                                var thirdpartydn = "";
                                if (datas.thirdpartydn) {
                                    thirdpartydn = datas.thirdpartydn.value;
                                }
                                if ($SC.logmaskedphoneno) {
                                    thirdpartydn = $SC.replacephonenum(thirdpartydn);
                                }
                                $F.alert(smsg + thirdpartydn);
                            }
                            $SC.CallInfo.CallParty.activeParties--;
                            if ($SC.CallInfo.CallParty.activeParties < 2) {
                                $SC.CallInfo.CallParty.activeParties = 0;
                            }
                        }
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_PARTYCHANGED:
                    case $CTI_CONST.CTI_MSG.EVT_RELEASED:
                        $SC.CallInfo.CallParty.activeParties--;
                        if ($SC.CallInfo.CallParty.activeParties < 2) {
                            $SC.CallInfo.CallParty.activeParties = 0;
                        }
                        break;
                    case $CTI_CONST.CTI_MSG.EVT_ABANDONED:
                        break;
                    //EVT_MONITOR: 100--班长监听、强插、接管，具体看userdata的monitortype
                    case 100:
                        if ($SC._callback_monitor) {
                            if (datas.userdata && datas.userdata.value) {
                                var monitor = datas.userdata.value.userdata.value;
                                //monitor: 1--班长，0--坐席
                                if (monitor.monitor == 1) {
                                    $SC.endmonitorcallback({"code": 0, "reason": "success"});
                                }
                            }
                        }
                        break;
                    default:
                }

                this.fireCTIEvent(datas);
                this.fireSCTIEvent(datas.event.value.toString(), datas);
                //if (m_to_save_event == 1) {
                if (m_to_save_event == 1 && $SC.CallInfo.CallState2 == $CTI_CONST.CALL_STATE.CS_TALKING) {
                    m_to_save_event = 0;
                    this.CallInfo.saveEvent(1);
                }

                if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_PARTYDELETED) {
                    $SC.fireSCTIEvent('callstatechange', datas, undefined, true);
                }
            },

            onOpen: function (evt) {
                //
            },

            onClose: function (evt) {
                if (m_softphonestep >= 11) {
                    m_softphonestep = 2;
                    if (this.agentState > $CTI_CONST.AGENT_STATE.EAS_LOGOUT) {
                        this.onCTIEvent({
                            data: '{"event":{"value":"15","type":1}}'
                        })
                    }
                }
                if (this.loginCallback) {
                    this.result.code = 'R_FAIL';
                    this.result.message = 'Login failed by sockect onClose';
                    this.err = evt;
                    this.loginCallback.incallback = true;
                    var ret = {};
                    ret.type = "socketclose";
                    logmsg("loginCallback", false, ret);
                    this.loginCallback.callback(this.result.code == 'R_OK', ret);
                    this.loginCallback = undefined;
                }
            },

            onError: function (evt) {
                //websocket connection error
                if (this.loginCallback) {
                    this.result.code = 'R_FAIL';
                    this.result.message = 'Login failed by sockect onError';
                    this.err = evt;
                    this.loginCallback.incallback = true;
                    var ret = {};
                    ret.type = "error";
                    logmsg("loginCallback", false, ret);
                    this.loginCallback.callback(this.result.code == 'R_OK');
                    this.loginCallback = undefined;
                }
            },

            onSendMessage: function (request) {
                //$F.log('SoftphoneCore - onSendMessage', request);
                //this.addlog('SoftphoneCore - onSendMessage', request, undefined, 'onSendMessage');
                logmsg("onSendMessage", request);
            },

            onLinkConnected: function (evt) {
                m_softphonestep = 21;
                cticlient.registerdn(this.dn);
                if (this.result) {
                    this.result.minStep = 'registerDN'
                }
            },

            onRegistered: function (evt) {
                m_softphonestep = 31;
                this.agentState = -1;
                this.agentLogin();
                if (this.result) {
                    this.result.minStep = 'agentLogin'
                }

            },

            onagentstate: function (datas, forcall, evttime) {
                var m_time,
                    m_agentstatechanged = false,
                    m_callstatechanged = false;

                if (forcall == 'callstatechange' || forcall == $CTI_CONST.CTI_MSG.EVT_RINGING + 1000) {
                    m_callstatechanged = true;
                    if (evttime) {
                        m_time = evttime;
                    } else {
                        m_time = this.getservertime(datas);
                    }
                }
                if (!m_callstatechanged) {
                    if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT || datas.event.value == $CTI_CONST.CTI_MSG.EVT_LINKDISCONNECTED || datas.event.value == $CTI_CONST.CTI_MSG.EVT_SERVERDISCONNECTED) {
                        if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT) {
                            m_softphonestep = 12;
                        } else {
                            m_softphonestep = 2;
                        }

                        if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_LOGOUT) {
                            return;
                        }
                        this.agentState = $CTI_CONST.AGENT_STATE.EAS_LOGOUT;
                        this.AgentState = this.agentState;
                        this.agentMode = 0;
                        this.reasonCode = 0;
                        m_time = this.getservertime(datas);
                        //this.m_logouttime = m_time;
                        m_logouttime = m_time;

                        this.onlogin(3);
                        /*
                        if (keepAliveTimer) {
                            clearInterval(keepAliveTimer);
                            keepAliveTimer = 0;
                        }
                         */
                        $SC.stopTimer(0, "","core.keepalive");

                        stopstatustimer();
                        this.fireSCTIEvent('OnLogout');

                        if (m_worktype) {
                            logmsg("m_worktype cleared from " + m_worktype + ' by OnLogout');
                            m_worktype = '';
                        }

                        m_agentstatechanged = true;
                    }

                    if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTLOGIN || datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTREADY || datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTNOTREADY) {
                        m_softphonestep = 32;

                        if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_LOGOUT || this.agentState < 0) {
                            this.agentState = $CTI_CONST.AGENT_STATE.EAS_UNKNOWN;
                            this.agentMode = 0;
                            this.reasonCode = 0;
                            m_time = this.getservertime(datas);
                            //this.m_logintime = m_time;
                            m_logintime = m_time;
                            this.onlogin(1);
                            /*
                            $.cookie("jssoftphone.extension", this.dn, {
                                expires: 30
                            });
                            $.cookie("jssoftphone.agentid", this.agentId, {
                                expires: 30
                            });
                            $.cookie("jssoftphone.queue", this.queue, {
                                expires: 30
                            });
                             */

                            localStorage.setItem("jssoftphone.extension", this.dn);
                            localStorage.setItem("jssoftphone.agentid", this.agentId);
                            localStorage.setItem("jssoftphone.queue", this.queue);

                            this.fireSCTIEvent('OnLogin');
                            if (m_conf.m_keepalive > 0) {
                                /*
                                if (keepAliveTimer) {
                                    clearInterval(keepAliveTimer);
                                }
                                keepAliveTimer = setInterval(function () {
                                    cticlient.keepalive();
                                    }, m_conf.m_keepalive);
                                 */
                                $SC.startTimer(m_conf.m_keepalive, 0, 0, "core.keepalive", function(counter, gap, time) {
                                    logmsg("softphone.core.keepalive " + counter + ", "  + gap + (time? ", " + time: ""));
                                    if (Math.abs(gap - m_conf.m_keepalive) > 500) {
                                        logmsg("interval abnormal for softphone.core.keepalive ", counter, gap, new Date());
                                    }
                                    cticlient.keepalive();
                                })
                            }

                            if (m_conf.m_LogonStatus) {
                                if (m_conf.m_LogonStatus === "ready") {
                                    setTimeout(function() {
                                        if ($SC.AgentState != 2) {
                                            $SC.agentReady(2);
                                        }
                                    }, 500);
                                } else if (m_conf.m_LogonStatus === "notready" || m_conf.m_LogonStatus === "aux") {
                                    setTimeout(function() {
                                        if ($SC.AgentState != 3) {
                                            $SC.agentNotReady2(3);
                                        }
                                    })
                                }
                            }

                            m_agentstatechanged = true;

                            if (this.loginCallback && this.result) {
                                this.result.code = 'R_OK';
                                this.result.message = '';
                                this.result.err = undefined;
                                this.loginCallback.incallback = true;
                                var ret = {};
                                ret.type = "success";
                                this.loginCallback.callback(this.result.code == 'R_OK', ret);
                                this.loginCallback = undefined;
                            }

                        } else if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_READY) {
                            if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTREADY) {
                                return;
                            }
                        } else if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_NOTREADY) {
                            if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTNOTREADY && datas.workmode.value == this.agentMode) {
                                if (this.agentMode == $CTI_CONST.AGENT_WORKMODE.AUX) {
                                    if ((datas.reasoncode) && parseInt(datas.reasoncode.value) == this.reasonCode) {
                                        return;
                                    }
                                } else {
                                    return;
                                }
                            }
                        }

                        if (!m_agentstatechanged) {
                            m_agentstatechanged = true;
                            m_time = this.getservertime(datas);
                        }
                        this.m_agent_status_detail_starttime = m_time;
                    }

                    if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTREADY) {
                        this.agentState = $CTI_CONST.AGENT_STATE.EAS_READY;
                        this.AgentState = this.agentState;
                        this.agentMode = datas.workmode.value;
                        this.reasonCode = 0;
                    }

                    if (datas.event.value == $CTI_CONST.CTI_MSG.EVT_AGENTNOTREADY) {
                        this.agentState = $CTI_CONST.AGENT_STATE.EAS_NOTREADY;
                        this.AgentState = this.agentState;
                        this.agentMode = datas.workmode.value;
                        if (this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW) {
                            this.reasonCode = 0;
                        } else {
                            if (datas.reasoncode) {
                                this.reasonCode = parseInt(datas.reasoncode.value);
                            } else {
                                this.reasonCode = 0;
                            }
                        }
                    }
                }

                if (m_agentstatechanged || m_callstatechanged) {
//softphone.agent_status_detail.insert.v201610=insert into Agent_Status_Detail{C1}(REC_GUID,AgentID,StartTime,EndTime,Status,WorkMode,DeviceDN,Queue,ANI,DNIS,CallType,ConnectionID,CallRelated,ReasonCode{C16}) values(@{C2}S,@{C3}S,@{C4}D,@{C5}D,@{C6}N,@{C7}N,@{C8}S,@{C9}S,@{C10}S,@{C11}S,@{C12}N,@{C13}S,@{C14}N,@{C15}S{C17})
//softphone.agent_status_detail.update.v201610=update agent_status_detail{C1} set endtime=@{C2}D where rec_guid=@{C3}S
                    //if (this.m_save_logagentstatusdetail == 1) {

                    if (m_save_logagentdateil == 1) {
                        if (this.m_agent_status_detail_guid) {
                            this.executeupdatesql("softphone.agent_status_detail.update.v201610", [$E.staff.epidSql, m_time, this.m_agent_status_detail_guid]);
                        }
                    }

                    if (forcall == 'OnCallEnd') {
                        //tbd: no save, or delay save?
                    }
                    if (forcall || this.CallInfo.CallState2 == 0) {
                        this.m_agent_status_detail_guid = Guid.raw();
                        //if (this.m_save_logagentstatusdetail == 1) {
                        if (m_save_logagentdateil == 1) {
                            //this.executeupdatesql("softphone.agent_status_detail.insert.v201610", [$E.staff.epidSql, this.m_agent_status_detail_guid, this.agentId, m_time, m_time, this.agentState, this.agentMode, this.dn, this.agentGroup, '', '', 0, '', 0, this.reasonCode]);
                            var m_state = undefined;
                            var m_mode = undefined;
                            if (forcall == $CTI_CONST.CTI_MSG.EVT_RINGING + 1000) {
                                m_mode = 101;
                            } else {
                                m_mode = this.CallInfo.CallState2;
                            }
                            if (m_mode) {
                                m_state = $CTI_CONST.AGENT_STATE.EAS_BUSY;
                            } else {
                                m_state = this.agentState;
                                m_mode = this.agentMode;
                            }
                            if (m_state == $CTI_CONST.AGENT_STATE.EAS_UNKNOWN) {
                                m_state = 1;
                                m_mode = 0;
                            } else if (m_state == $CTI_CONST.AGENT_STATE.EAS_LOGOUT) {
                                m_state= 5;
                                m_mode = 0;
                            }
                            this.executeupdatesql("softphone.agent_status_detail.insert.v201610", [$E.staff.epidSql, this.m_agent_status_detail_guid, this.agentId, m_time, m_time, m_state, m_mode, this.dn, this.agentGroup, '', '', 0, '', 0, this.reasonCode, ',STAFF_ID', ",'" + $E.staff.id + "'"]);
                        }
                    }

                    startstatustimer();
                    if (m_agentstatechanged) {
                        this.fireSCTIEvent('agentstatechange');
                    }

                    var duration = Math.floor((new Date(m_time).valueOf() - new Date(m_agent_stat.statetime).valueOf()) / 1000);
                    if (duration < 0) {
                        duration = 0;
                        logmsg("SoftphoneCore -- warning: current cti time is " + m_time + ", last cti time is " + m_agent_stat.statetime);
                    }

                    //for Call End, calc callrelated values
                    if ($SC.CallInfo.CallState2 == 0 && (m_agent_stat.agentstate >= AGSTATE.AS_BUSY && m_agent_stat.agentstate != AGSTATE.AS_LOGOUT)) {
                        var t1 = Math.floor((new Date($SC.CallInfo.EndTime).valueOf() - new Date($SC.CallInfo.StartTime).valueOf()) / 1000);
                        if (t1 < 0) {
                            t1 = 0;
                            logmsg("SoftphoneCore -- warning: current call endtime is " + $SC.CallInfo.EndTime + ", call starttime is " + $SC.CallInfo.StartTime);
                        }
                        var t2 = 0;
                        if ($SC.CallInfo.EstablishTime) {
                            t2 = Math.floor((new Date($SC.CallInfo.EndTime).valueOf() - new Date($SC.CallInfo.EstablishTime).valueOf()) / 1000);
                            if (t2 < 0) {
                                t2 = 0;
                                logmsg("SoftphoneCore -- warning: current call endtime is " + $SC.CallInfo.EndTime + ", call establishtime is " + $SC.CallInfo.EstablishTime);
                            }
                        }
                        if ($SC.CallInfo.CallType == 3) {
                            m_agent_stat.totalob = (m_agent_stat.totalob || 0) + 1;
                            m_agent_stat.totalobtime = (m_agent_stat.totalobtime || 0) + t1;
                            if ($SC.CallInfo.EstablishTime) {
                                m_agent_stat.totalobtalk = (m_agent_stat.totalobtalk || 0) + 1;
                                m_agent_stat.totalobtalktime = (m_agent_stat.totalobtalktime || 0) + t2;
                                if (!m_agent_stat.maxobtalktime || m_agent_stat.maxobtalktime < t2) {
                                    m_agent_stat.maxobtalktime = t2;
                                }
                            }
                        } else {
                            m_agent_stat.totalib = (m_agent_stat.totalib || 0) + 1;
                            m_agent_stat.totalibtime = (m_agent_stat.totalibtime || 0) + t1;
                            if ($SC.CallInfo.EstablishTime) {
                                m_agent_stat.totalibtalk = (m_agent_stat.totalibtalk || 0) + 1;
                                m_agent_stat.totalibtalktime = (m_agent_stat.totalibtalktime || 0) + t2;
                                if (!m_agent_stat.maxibtalktime || m_agent_stat.maxibtalktime < t2) {
                                    m_agent_stat.maxibtalktime = t2;
                                }
                            }
                        }
                    }

                    if (m_agent_stat.agentstate == AGSTATE.AS_NOTREADY && m_agent_stat.workmode == 4 && ($SC.CallInfo.CallState2 > 0 || (this.agentState != 3 || this.agentMode != 4))) {
                        if (m_agent_stat.calltype == 3) {
                            m_agent_stat.totalobacwtime = (m_agent_stat.totalobacwtime || 0) + duration;
                            if (!m_agent_stat.maxobacwtime || m_agent_stat.maxobacwtime < duration) {
                                m_agent_stat.maxobacwtime = duration;
                            }
                        } else {
                            m_agent_stat.totalibacwtime = (m_agent_stat.totalibacwtime || 0) + duration;
                            if (!m_agent_stat.maxibacwtime || m_agent_stat.maxibacwtime < duration) {
                                m_agent_stat.maxibacwtime = duration;
                            }
                        }
                    }
                    if ($SC.CallInfo.CallState2 == 0 && m_agent_stat.callrelated == 0) {
                        if (m_agent_stat.agentstate == AGSTATE.AS_READY) {
                            m_agent_stat.readytime = m_agent_stat.readytime + duration;
                            if (m_agent_stat.maxreadytime < duration) {
                                m_agent_stat.maxreadytime = duration;
                            }
                        }
                        if (m_agent_stat.agentstate == AGSTATE.AS_NOTREADY) {
                            if (m_agent_stat.workmode == 3) {
                                m_agent_stat.auxtime = m_agent_stat.auxtime + duration;
                                if (m_agent_stat.maxauxtime < duration) {
                                    m_agent_stat.maxauxtime = duration;
                                }
                                if (m_agent_stat.reasoncode > 0) {
                                    m_agent_stat.reasonallcount = m_agent_stat.reasonallcount + 1;
                                    m_agent_stat.reasonalltime = m_agent_stat.reasonalltime + duration;
                                }
                                switch (m_agent_stat.reasoncode) {
                                    case 0:
                                        break;
                                    case 1:
                                        m_agent_stat.reason1count = m_agent_stat.reason1count + 1;
                                        m_agent_stat.reason1time = m_agent_stat.reason1time + duration;
                                        break;
                                    case 2:
                                        m_agent_stat.reason2count = m_agent_stat.reason2count + 1;
                                        m_agent_stat.reason2time = m_agent_stat.reason2time + duration;
                                        break;
                                    case 3:
                                        m_agent_stat.reason3count = m_agent_stat.reason3count + 1;
                                        m_agent_stat.reason3time = m_agent_stat.reason3time + duration;
                                        break;
                                    case 4:
                                        m_agent_stat.reason4count = m_agent_stat.reason4count + 1;
                                        m_agent_stat.reason4time = m_agent_stat.reason4time + duration;
                                        break;
                                    case 5:
                                        m_agent_stat.reason5count = m_agent_stat.reason5count + 1;
                                        m_agent_stat.reason5time = m_agent_stat.reason5time + duration;
                                        break;
                                    case 6:
                                        m_agent_stat.reason6count = m_agent_stat.reason6count + 1;
                                        m_agent_stat.reason6time = m_agent_stat.reason6time + duration;
                                        break;
                                    case 7:
                                        m_agent_stat.reason7count = m_agent_stat.reason7count + 1;
                                        m_agent_stat.reason7time = m_agent_stat.reason7time + duration;
                                        break;
                                    case 8:
                                        m_agent_stat.reason8count = m_agent_stat.reason8count + 1;
                                        m_agent_stat.reason8time = m_agent_stat.reason8time + duration;
                                        break;
                                    case 9:
                                        m_agent_stat.reason9count = m_agent_stat.reason9count + 1;
                                        m_agent_stat.reason9time = m_agent_stat.reason9time + duration;
                                        break;
                                    default:
                                }
                            }
                        }
                    }
                    m_agent_stat.logintime = m_agent_stat.logintime + duration;

                    m_agent_stat.statetime = m_time;
                    if ($SC.CallInfo.CallState2 != 0 || (this.agentState == "3" && this.agentMode == "4")) {
                        m_agent_stat.reasoncode = 0;
                        m_agent_stat.connectionid = "";
                        m_agent_stat.callrelated = 1;
                        m_agent_stat.calltype = $SC.CallInfo.CallType;
                        m_agent_stat.ani = $SC.CallInfo.ANI;
                        m_agent_stat.dnis = $SC.CallInfo.DNIS;
                        if ($SC.CallInfo.CallState2 != 0) {
                            /*
							m_agent_stat.agentstate = 4;
							m_agent_stat.workmode = $SC.CallInfo.CallState2;
							 */
                            m_agent_stat.agentstate = CALLSTATEMAP[$SC.CallInfo.CallState2] || AGSTATE.AS_BUSY;
                            m_agent_stat.workmode = 0;
                        } else {
                            m_agent_stat.agentstate = AGSTATE.AS_NOTREADY;
                            //m_agent_stat.agentstate = this.agentState;
                            m_agent_stat.workmode = this.agentMode;
                        }
                    } else {
                        if (this.agentState === 1) {
                            m_agent_stat.agentstate = AGSTATE.AS_LOGOUT;
                        } else if (this.agentState === 3) {
                            if ($SC.agentMode === 4) {
                                m_agent_stat.agentstate = AGSTATE.AS_NOTREADY;
                            } else {
                                m_agent_stat.agentstate = AGSTATE.AS_NOTREADY;
                            }
                        } else {
                            m_agent_stat.agentstate = this.agentState;
                        }
                        m_agent_stat.workmode = this.agentMode;
                        m_agent_stat.reasoncode = $SC.reasonCode;
                        m_agent_stat.connectionid = "";
                        m_agent_stat.callrelated = 0;
                        m_agent_stat.calltype = 0;
                        m_agent_stat.ani = "";
                        m_agent_stat.dnis = "";
                    }
                    if (m_save_agentcurrentstate == 1) {
                        $SC.saveagentcurrentstate(2);
                    }
                    if (m_save_stagenttoday == 1) {
                        $SC.savestaagenttoday(2);
                    }
                }
            },

            //ifor : 1--login, 2--pulse, 3--logout
            onlogin: function (ifor) {
                if (!ifor) {
                    ifor = 1;
                }
                switch (ifor) {
                    case 1:
                        this.CallInfo = new CallInfos();
//softphone.agent_login_info.insert.v201610=insert into Agent_Login_Info{C1}(REC_GUID,AgentID,LoginTime,LogoutTime,DeviceDN,Queue{C8}) values(@{C2}S,@{C3}S,@{C4}D,@{C5}D,@{C6}S,@{C7}S{C9})
                        m_agent_login_guid = Guid.raw();
                        m_logouttime = undefined;
                        //this.logouttime = undefined;
                        //if (!this.logintime){
                        //	this.logintime = this.getservertime();
                        //}

                        this.LoginInfo.agent_login_guid = m_agent_login_guid;
                        this.LoginInfo.logintime = m_logintime;
                        this.LoginInfo.logouttime = undefined;
                        this.LoginInfo.logined = true;

                        //if (this.m_save_logagentlogininfo == 1) {
                        if (m_save_logagentlogininfo == 1) {
                            //this.executeupdatesql("softphone.agent_login_info.insert.v201610", [$E.staff.epidSql, m_agent_login_guid, this.agentId, m_logintime, m_logintime, this.dn, this.agentGroup]);
                            this.executeupdatesql("softphone.agent_login_info.insert.v201610", [$E.staff.epidSql, m_agent_login_guid, this.agentId, m_logintime, m_logintime, this.dn, this.agentGroup, ',STAFF_ID', ",'" + $E.staff.id + "'"]);
                        }
                        m_agent_stat = {};
                        m_agent_stat.curlogintime = m_logintime;
                        m_agent_stat.agentid = this.agentId;
                        m_agent_stat.statetime = m_logintime;
                        m_agent_stat.agentstate = 1;
                        m_agent_stat.workmode = 0;
                        m_agent_stat.devicedn = this.dn;
                        m_agent_stat.queue = this.agentGroup;
                        m_agent_stat.connectionid = '';
                        m_agent_stat.callrelated = 0;
                        m_agent_stat.calltype = 0;
                        m_agent_stat.ani = '';
                        m_agent_stat.dnis = '';
                        m_agent_stat.vdn = '';
                        m_agent_stat.reasoncode = 0;

                        if (m_save_agentcurrentstate == 1) {
                            var r = this.executeselectsql("softphone.agent_current_state", [this.agentId]);
                            if (r && r.code > 0 && r.value && r.value[0].count > 0) {
                            } else {
                                //this.executeupdate("softphone.agent_current_state.insert",[m_agent_stat.agentid,m_agent_stat.statetime,m_agent_stat.agentstate,m_agent_stat.workmode,m_agent_stat.devicedn,m_agent_stat.queue,m_agent_stat.connectionid,m_agent_stat.callrelated,m_agent_stat.caltype,m_agent_stat.ani,m_agent_stat.dnis,m_agent_stat.vdn,m_agent_stat.reasoncode],true)
                                this.saveagentcurrentstate(1);
                            }
                        }

                        if (m_save_stagenttoday == 1) {
                            var btoday = false;
                            //softphone.sta_agent_today=select startdate,staff_id,agentid,logintime,readytime,maxreadytime,auxtime,maxauxtime,totalib,totalibtalk,totalibtime,totalibtalktime,maxibtalktime,totalibacwtime,maxibacwtime,totalob,totalobtalk,totalobtime,totalobtalktime,maxobtalktime,totalobacwtime,maxobacwtime,reason1count,reason1time,reason2count,reason2time,reason3count,reason3time,reason4count,reason4time,reason5count,reason5time,reason6count,reason6time,reason7count,reason7time,reason8count,reason8time,reason9count,reason9time,reasonallcount,reasonalltime from sta_agent_today where staff_id='{C_BY}'
                            var r = this.executeselectsql("softphone.sta_agent_today", [this.agentId]);
                            if (r && r.code > 0 && r.value && r.value[0].count > 0) {
                                var tv = r.value[0].fields[0];
                                if (r.value[0].count == 1) {
                                    var dt = new Date(r.value[0].fields[0][0]);
                                    var dt0 = new Date();
                                    if (dt && dt0.getDate() == dt.getDate() && dt0.getMonth() == dt.getMonth() && dt0.getFullYear() == dt.getFullYear()) {
                                        btoday = true;
                                    }
                                }
                                if (!btoday) {
                                    this.executeupdate("softphone.sta_agent_today.delete", [this.agentId]);
                                } else {
                                    m_agent_stat.logintime = tv[3] || 0;
                                    m_agent_stat.readytime = tv[4] || 0;
                                    m_agent_stat.maxreadytime = tv[5] || 0;
                                    m_agent_stat.auxtime = tv[6] || 0;
                                    m_agent_stat.maxauxtime = tv[7] || 0;
                                    m_agent_stat.totalib = tv[8] || 0;
                                    m_agent_stat.totalibtalk = tv[9] || 0;
                                    m_agent_stat.totalibtime = tv[10] || 0;
                                    m_agent_stat.totalibtalktime = tv[11] || 0;
                                    m_agent_stat.maxibtalktime = tv[12] || 0;
                                    m_agent_stat.totalibacwtime = tv[13] || 0;
                                    m_agent_stat.maxibacwtime = tv[14] || 0;
                                    m_agent_stat.totalob = tv[15] || 0;
                                    m_agent_stat.totalobtalk = tv[16] || 0;
                                    m_agent_stat.totalobtime = tv[17] || 0;
                                    m_agent_stat.totalobtalktime = tv[18] || 0;
                                    m_agent_stat.maxobtalktime = tv[19] || 0;
                                    m_agent_stat.totalobacwtime = tv[20] || 0;
                                    m_agent_stat.maxobacwtime = tv[21] || 0;
                                    m_agent_stat.reason1count = tv[22] || 0;
                                    m_agent_stat.reason1time = tv[23] || 0;
                                    m_agent_stat.reason2count = tv[24] || 0;
                                    m_agent_stat.reason2time = tv[25] || 0;
                                    m_agent_stat.reason3count = tv[26] || 0;
                                    m_agent_stat.reason3time = tv[27] || 0;
                                    m_agent_stat.reason4count = tv[28] || 0;
                                    m_agent_stat.reason4time = tv[29] || 0;
                                    m_agent_stat.reason5count = tv[30] || 0;
                                    m_agent_stat.reason5time = tv[31] || 0;
                                    m_agent_stat.reason6count = tv[32] || 0;
                                    m_agent_stat.reason6time = tv[33] || 0;
                                    m_agent_stat.reason7count = tv[34] || 0;
                                    m_agent_stat.reason7time = tv[35] || 0;
                                    m_agent_stat.reason8count = tv[36] || 0;
                                    m_agent_stat.reason8time = tv[37] || 0;
                                    m_agent_stat.reason9count = tv[38] || 0;
                                    m_agent_stat.reason9time = tv[39] || 0;
                                    m_agent_stat.reasonallcount = tv[40] || 0;
                                    m_agent_stat.reasonalltime = tv[41] || 0;
                                }
                            }
                            if (!btoday) {
                                m_agent_stat.logintime = 0;
                                m_agent_stat.readytime = 0;
                                m_agent_stat.maxreadytime = 0;
                                m_agent_stat.auxtime = 0;
                                m_agent_stat.maxauxtime = 0;
                                m_agent_stat.totalib = 0;
                                m_agent_stat.totalibtalk = 0;
                                m_agent_stat.totalibtime = 0;
                                m_agent_stat.totalibtalktime = 0;
                                m_agent_stat.maxibtalktime = 0;
                                m_agent_stat.totalibacwtime = 0;
                                m_agent_stat.maxibacwtime = 0;
                                m_agent_stat.totalob = 0;
                                m_agent_stat.totalobtalk = 0;
                                m_agent_stat.totalobtime = 0;
                                m_agent_stat.totalobtalktime = 0;
                                m_agent_stat.maxobtalktime = 0;
                                m_agent_stat.totalobacwtime = 0;
                                m_agent_stat.maxobacwtime = 0;
                                m_agent_stat.reason1count = 0;
                                m_agent_stat.reason1time = 0;
                                m_agent_stat.reason2count = 0;
                                m_agent_stat.reason2time = 0;
                                m_agent_stat.reason3count = 0;
                                m_agent_stat.reason3time = 0;
                                m_agent_stat.reason4count = 0;
                                m_agent_stat.reason4time = 0;
                                m_agent_stat.reason5count = 0;
                                m_agent_stat.reason5time = 0;
                                m_agent_stat.reason6count = 0;
                                m_agent_stat.reason6time = 0;
                                m_agent_stat.reason7count = 0;
                                m_agent_stat.reason7time = 0;
                                m_agent_stat.reason8count = 0;
                                m_agent_stat.reason8time = 0;
                                m_agent_stat.reason9count = 0;
                                m_agent_stat.reason9time = 0;
                                m_agent_stat.reasonallcount = 0;
                                m_agent_stat.reasonalltime = 0;

                                //this.executeupdate("softphone.sta_agent_today.insert",[m_agent_stat.agentid,m_agent_stat.statetime,m_agent_stat.agentstate,m_agent_stat.workmode,m_agent_stat.devicedn,m_agent_stat.queue,m_agent_stat.connectionid,m_agent_stat.callrelated,m_agent_stat.calltype,m_agent_stat.ani,m_agent_stat.dnis,m_agent_stat.vdn,m_agent_stat.reasoncode],true)
                                this.savestaagenttoday(1);
                            }
                        }

                        break;
                    case 2:

                    case 3:
                        //if (!this.logouttime){
                        //	this.logouttime = this.getservertime();
                        if (!m_logouttime) {
                            m_logouttime = this.getservertime();
                        }
                        //this.LoginInfo.agent_login_guid = this.agent_login_guid;
                        //this.LoginInfo.logintime = this.logintime;
                        this.LoginInfo.logouttime = m_logouttime;
                        this.LoginInfo.logined = false;

                        //softphone.agent_login_info.update.v201610=update Agent_Login_Info{C1} set LogoutTime=@{C2}D where rec_guid=@{C3}S
                        //if (this.m_save_logagentlogininfo == 1) {
                        if (m_save_logagentlogininfo == 1) {
                            if (m_agent_login_guid) {
                                this.executeupdatesql("softphone.agent_login_info.update.v201610", [$E.staff.epidSql, m_logouttime, m_agent_login_guid]);
                            }
                        }
                        break;
                }
            },

            /**
             * 工号登录cti
             * @param agentId
             * @param agentPassword
             * @param agentGroup
             * @param workMode
             * @param acdAgent
             */
            login: function (agentId, dn, agentPassword, agentGroup, workMode, acdAgent) {
                this._getini(false, agentId, dn);
                switch (m_softphonestep) {
                    case 0:
                    case 1:
                    case 3:
                    case 2:
                        if (agentId) {
                            this.agentId = agentId;
                            this.agentID = agentId;
                        }
                        //if (dn) {
                            this.dn = dn;
                            this.extension = dn;
                        //}
                        //if (agentPassword) {
                        //    this.agentPassword = agentPassword;
                        if (this.loginparams) {
                            this.agentPassword = this.loginparams.agentPassword || this.loginparams.password;
                            //this.agentPassword = agentPassword;
                            //if (this.agentPassword) {
                        } else if (m_conf.m_defaultpassword) {
                            this.agentPassword = m_conf.m_defaultpassword.replace(/\[agentid\]/ig, this.agentId).replace(/\[extension\]/ig, this.dn);
                        }
                        if (agentGroup) {
                            this.agentGroup = agentGroup;
                        } else {
                            this.agentGroup = "";
                        }
                        if (workMode) {
                            this.agentMode = workMode;
                        } else {
                            //this.agentMode = $CTI_CONST.AGENT_WORKMODE.MANUALIN;
                            this.agentMode = m_conf.m_autoWorkMode;
                        }
                        if (acdAgent) {
                            this.acdAgent = acdAgent;
                        } else {
                            this.acdAgent = 1;
                        }

                        m_softphonestep = 11;
                        logmsg("SoftphoneCore -- connectserver");
                        cticlient.connectserver($E.wsctiServer || this.parseserverurl(this._getconfig('CTI', 'ServerEndPoint', agentId, dn)), this.onOpen.bind(this), this.onClose.bind(this), this.onCTIEvent.bind(this), this.onError.bind(this), this.onSendMessage.bind(this), agentId, dn, agentPassword, agentGroup);
                        if (this.result) {
                            this.result.minStep = 'connectServer';
                        }
                        break;
                    case 12:
                        if (agentId) {
                            this.agentId = agentId;
                            this.agentID = agentId;
                        }
                        //if (dn) {
                            this.dn = dn;
                            this.extension = dn;
                        //}
                        //if (agentPassword) {
                        if (this.loginparams) {
                            this.agentPassword = this.loginparams.agentPassword || this.loginparams.password;
                        //this.agentPassword = agentPassword;
                        //if (this.agentPassword) {
                        } else if (m_conf.m_defaultpassword) {
                            this.agentPassword = m_conf.m_defaultpassword.replace(/\[agentid\]/ig, this.agentId).replace(/\[extension\]/ig, this.dn);
                        }
                        if (agentGroup) {
                            this.agentGroup = agentGroup;
                        } else {
                            this.agentGroup = "";
                        }
                        if (workMode) {
                            this.agentMode = workMode;
                        } else {
                            this.agentMode = $CTI_CONST.AGENT_WORKMODE.MANUALIN;
                        }
                        if (acdAgent) {
                            this.acdAgent = acdAgent;
                        } else {
                            this.acdAgent = 1;
                        }
                        this.onLinkConnected();
                        break;
                    default:
                }
            },

            login2: function (params) {
                var softphoneCore = this;
                if (!params) {
                    params = {};
                }
                this.loginparams = params;
                softphoneCore.result = {
                    code: 'R_INPROC',
                    mainStep: 'CTI',
                    minStep: ''
                };
                /*
            	if (softphoneCore.loginCallback) {
            		//alert('Prev login request is been processing');
            		softphoneCore.result.code = 'R_REFUSE';
            		softphoneCore.result.message = 'Prev login request is been processing';
            		return;
            	}
            	*/
                //cticlient.connectserver($E.wsctiServer || this.getConfig('CTI', 'ServerEndPoint'), this.onOpen.bind(this), this.onClose.bind(this), this.onCTIEvent.bind(this), this.onError.bind(this), this.onSendMessage.bind(this));
                softphoneCore.loginCallback = {
                    callback: params.callback,
                    loginTime: new Date().getTime(),
                    incallback: false
                };
                //if (m_softphonestep > 13) {
                if (m_softphonestep > 10) {
                    logmsg("in login2, m_softphonestep change to 2 from " + m_softphonestep)
                    m_softphonestep = 2;
                }
                var pw = params.password || params.agentPassword;

                if (!pw) {
                    //pw = m_conf.m_defaultpassword.replace(/\[agentid\]/ig, this.agentId).replace(/\[extension\]/ig, this.dn);
                    pw = m_conf.m_defaultpassword.replace(/\[agentid\]/ig, params.agentId).replace(/\[extension\]/ig, this.dn);
                    params.agentPassword = pw;
                }
                softphoneCore.login(params.agentId, params.dn, pw, params.agentGroup || params.queue, params.workMode, params.acdAgent);

                //start timer
                function checkLoginTimer() {
                    setTimeout(function () {
                        if (softphoneCore.loginCallback && !softphoneCore.loginCallback.incallback) {
                            var nowTime = new Date().getTime();
                            if (nowTime - softphoneCore.loginCallback.loginTime > m_timeout_login) {
                                //timeout
                                softphoneCore.result.code = 'R_TIMEDOUT';
                                softphoneCore.result.message = 'Login failed by timed out';
                                var ret = {};
                                ret.type = "timeout";
                                softphoneCore.loginCallback.callback(softphoneCore.result.code == 'R_OK', ret);
                            } else {
                                checkLoginTimer();
                            }
                        }
                    }, 100);
                }

                if (softphoneCore.loginCallback) {
                    checkLoginTimer();
                }
            },

            agentLogin: function () {
                cticlient.login(this.agentId, this.dn, this.agentPassword, this.agentGroup, this.agentMode, this.acdAgent);
            },

            agentLogout: function (params) {
                var softphoneCore = this;
                var callback = undefined;
                if ($.isFunction(params)) {
                    callback = params;
                } else if (params && typeof (params) === "object") {
                    callback = params.callback;
                }
                if ($.isFunction(callback)) {
                    logmsg("SoftphoneCore -- agentLogout with callback");
                    this.result = {
                        code: 'R_INPROC',
                        mainStep: 'CTI',
                        minStep: 'agentLogout'
                    };

                    this.logoutCallback = {
                        callback: params.callback,
                        logoutTime: new Date().getTime()
                    };
                } else {
                    logmsg("SoftphoneCore -- agentLogout");
                    this.logoutCallback = undefined;
                }

                //tbd20190625
                if (m_conf.m_canlogoutinwork != 1) {
                    if (m_worktype || this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW) {
                        logmsg('SoftphoneCore -- agentLogout ignored for WorkType = ' + m_worktype + ', agentMode = ' + this.agentMode);
                        $F.alert(softphone.log("common.msg.endworkfirst", "请先结束当前的工作处理状态。"));
                        this.result.code = 'R_FAIL';
                        this.result.message = 'logout failed by agentstate';
                        if (softphoneCore.logoutCallback) {
                            softphoneCore.logoutCallback.callback(softphoneCore.result.code == 'R_OK');
                            softphoneCore.logoutCallback = undefined;
                        }
                        return false;
                    }
                }

                if (this.CallInfo.CallState2 > 0) {
                    //if (m_logoutconfirmoncall && !confirm('当前在通话中，确定要登出吗？')) {
                    if (m_logoutconfirmoncall && !confirm($SC.lang("common.confirm.logoutoncall", "当前在通话中，确定要登出吗？"))) {
                        logmsg('SoftphoneCore -- agentLogout ignored for CallState2 = ' + this.CallInfo.CallState2);
                        $F.alert($SC.lang("common.msg.nologoutoncall","通话状态不允许登出。"));
                        this.result.code = 'R_FAIL';
                        this.result.message = 'logout failed by callstate';
                        if (softphoneCore.logoutCallback) {
                            softphoneCore.logoutCallback.callback(softphoneCore.result.code == 'R_OK');
                            softphoneCore.logoutCallback = undefined;
                        }
                        return false;
                    } else {
                        logmsg('SoftphoneCore -- agentLogout confirmed with CallState2 = ' + this.CallInfo.CallState2);
                    }
                }

                cticlient.agentlogout();

                function checkLogoutTimer() {
                    setTimeout(function () {
                        if (softphoneCore.logoutCallback) {

                            if (softphoneCore.agentState <= $CTI_CONST.AGENT_STATE.EAS_LOGOUT) {
                                softphoneCore.result.code = 'R_OK';
                                softphoneCore.result.message = 'Logout ok';
                                softphoneCore.logoutCallback.callback(softphoneCore.result.code == 'R_OK');
                                softphoneCore.loginCallback = undefined;
                                return;
                            }

                            var nowTime = new Date().getTime();
                            if (nowTime - softphoneCore.logoutCallback.logoutTime > 30000) {
                                //timeout
                                softphoneCore.result.code = 'R_TIMEDOUT';
                                softphoneCore.result.message = 'Logout failed by timed out';
                                softphoneCore.logoutCallback.callback(softphoneCore.result.code == 'R_OK');
                                softphoneCore.loginCallback = undefined;
                            } else {
                                checkLogoutTimer();
                            }
                        }
                    }, 100);
                }

                if (softphoneCore.logoutCallback) {
                    checkLogoutTimer();
                }
            },

            answerCall: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - answerCall', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("answerCall", "request ingored for not login");
                    return false;
                }

                var call = this.CallInfo.getRingingCall();
                if (call) {
                    cticlient.answercall(call.connectionid);
                }
            },

            makeCall: function (phoneno, userdatas) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - makeCall', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("makeCall", "request ingored for not login");
                    return false;
                }

                var swarning = undefined;
                if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_READY) {
                    if (m_conf.m_MakeCallOnReady != 1) {
                        swarning = $SC.lang("common.msg.cannotcallout", "当前状态不允许外呼");
                    }
                }
                if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_NOTREADY) {
                    if (m_conf.m_MakeCallOnNotReady == 1) {
                    } else if (m_conf.m_MakeCallOnNotReady == 2) {
                        if (this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW) {
                            swarning = $SC.lang("common.msg.cannotcallout", "当前状态不允许外呼");
                        }
                    } else if (m_conf.m_MakeCallOnNotReady == 3) {
                        if (this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW) {
                            this.agentNotReady(3, {nodelay: 1})
                        }
                    } else {
                        swarning = $SC.lang("common.msg.cannotcallout", "当前状态不允许外呼");
                    }
                }
                if (swarning) {
                    logmsg(swarning);
                    $F.alert(swarning);
                    return false;
                }

                var ud = this.userdata2jsonuserdata(userdatas)
                ud = this.addcalloutdata(phoneno, ud);

                /* just for testing */
                if (m_OBCheckPhoneNo == 1) {
                    logmsg("::makeCall: " + phoneno + ", checkphoneno first");
                    var procedureObj = {};
                    procedureObj.name = "sp_obcheckphoneno";
                    var procparams = {
                        "@PhoneNo": phoneno
                        , "@Project_ID": $E.getActiveProject().id
                        , "@Rolegroup_ID": $E.staff.current.groupId
                        , "@Staff_ID": $E.staff.id
                        , "@AgentID": cticlient.agentid
                        , "@Extension": cticlient.dn
                        , "@CheckRet": 0
                        , "@CheckMsg": ''
                        , "@OutPhoneNo": ''
                        , "@Return_Value": 0
                    };
                    procedureObj.params = procparams;
                    procedureObj.callback = function (data) {
                        var ret;
                        var retv = data.value;
                        if (data.code == 1) {
                            if (retv[0] == 0 && retv[1] >= 0) {
                                if (retv[2] && phoneno != retv[2]) {
                                    logmsg("::makeCall: " + phoneno + " changed to " + retv[2] + ", in checkphoneno");
                                    phoneno = retv[2];
                                }
                                m_outphone = phoneno;
                                phoneno = $SC.addprefix(phoneno);
                                //ret = cticlient.makecall(phoneno, userdatas);
                                ret = cticlient.makecall(phoneno, userdatas);
                                return;
                            }
                        }
                        swarning = $SC.lang("common.msg.phonenocheckfail", "号码检查未通过");
                        if (data.code != 1) {
                            swarning = swarning + "：" + data.code;
                        }
                        if (retv && retv.length > 2) {
                            swarning = swarning + ", " + retv[2];
                        }
                        logmsg(swarning);
                        $F.alert(swarning);
                    };
                    $SC.execprocedure(procedureObj);
                } else {
                    var ret;
                    m_outphone = phoneno;
                    phoneno = this.addprefix(phoneno);
                    //ret = cticlient.makecall(phoneno, userdatas);
                    ret = cticlient.makecall(phoneno, ud);
                    if (ret == undefined) {
                        ret = true;
                    }
                    return ret;
                }
            },

            releaseCall: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - releaseCall', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("releaseCall", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (call) {
                    this.CallInfo.releaseaction = {"action": "releasecall", "actiontime": new Date().valueOf()};
                    cticlient.releasecall(call.connectionid);
                }
                call = this.CallInfo.getDialingCall();
                if (call) {
                    this.CallInfo.releaseaction = {"action": "releasecall", "actiontime": new Date().valueOf()};
                    cticlient.releasecall(call.connectionid);
                }
                call = this.CallInfo.getHeldCall();
                if (call) {
                    this.CallInfo.releaseaction = {"action": "releasecall", "actiontime": new Date().valueOf()};
                    ret = cticlient.releasecall(call.connectionid);
                }
                if (ret == undefined) {
                    ret = true;
                }
                //this.CallInfo.releaseaction = {"action": "releasecall", "actiontime": new Date().valueOf()};
                return ret;
            },

            holdCall: function (params) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - holdCall', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("holdCall", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (call) {
                    ret = cticlient.holdcall(call.connectionid, params);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            retrieveCall: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - retrieveCall', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("retrieveCall", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getHeldCall();
                if (call) {
                    ret = cticlient.retrievecall(call.connectionid);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            gettransferflags: function (callid, userdatas, conference) {
                f_autocomplete = '';
                conn_autocomplete = callid;

                if (userdatas) {
                    if (this.getdatabykey(userdatas, 'AutoComplete')) {
                        f_autocomplete = 'completetransferwhendialing';
                        userdatas = this.removedatabykey(userdatas, 'AutoComplete');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteConferenceWhenDialing')) {
                        f_autocomplete = 'completetransferwhendialing';
                        userdatas = this.removedatabykey(userdatas, 'CompleteConferenceWhenDialing');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteConferenceWhenNR')) {
                        f_autocomplete = 'completetransferwhennr';
                        userdatas = this.removedatabykey(userdatas, 'CompleteConferenceWhenNR');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteConferenceWhenRB')) {
                        f_autocomplete = 'completetransferwhenrb';
                        userdatas = this.removedatabykey(userdatas, 'CompleteConferenceWhenRB');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteConferenceWhenEstablish')) {
                        f_autocomplete = 'completetransferwhenestablish';
                        userdatas = this.removedatabykey(userdatas, 'CompleteConferenceWhenEstablish');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteWhenDialing')) {
                        f_autocomplete = 'completetransferwhendialing';
                        userdatas = this.removedatabykey(userdatas, 'CompleteWhenDialing');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteWhenNR')) {
                        f_autocomplete = 'completetransferwhennr';
                        userdatas = this.removedatabykey(userdatas, 'CompleteWhenNR');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteWhenRB')) {
                        f_autocomplete = 'completetransferwhenrb';
                        userdatas = this.removedatabykey(userdatas, 'CompleteWhenRB');
                    }
                    if (this.getdatabykey(userdatas, 'CompleteWhenEstablish')) {
                        f_autocomplete = 'completetransferwhenestablish';
                        userdatas = this.removedatabykey(userdatas, 'CompleteWhenEstablish');
                    }
                    if (conference) {
                        f_autocomplete = f_autocomplete.replace('transfer', 'conference');
                    }
                }
                if (f_autocomplete) {
                    $SC.addconsolelog("SoftphoneCore-f_autocomplete=" + f_autocomplete + ",conn_autocomplete=" + conn_autocomplete);
                }
                return userdatas;
            },

            initTransfer: function (phoneno, userdatas) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - initTransfer', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("initTransfer", "request ingored for not login");
                    return false;
                }

                //$SC.addconsolelog("SoftphoneCore-initTransfer(" + phoneno + "," + userdatas + ")");
                logmsg("initTransfer", phoneno , userdatas);

                /*
            	if (!userdatas && m_conf.traninternalani) {
            	    if ($SC.CallInfo.ANI == $SC.dn) {
            	        userdatas = m_conf.traninternalani + '=' + $SC.CallInfo.DNIS;
                    } else {
                        userdatas = m_conf.traninternalani + "=" + $SC.CallInfo.ANI;
                    }
                }
            	 */

                var ret;
                var call = this.CallInfo.getActiveCall();
                //var call = {};
                if (call) {
                    this.CallInfo.transferflag = 1;
                    this.CallInfo.transferdest = phoneno;
                    m_dest = phoneno;
                    //userdatas = this.userdata2jsonuserdata(userdatas);
                    //userdatas = this.adduserdata(userdatas, 'E_Dest', 3, m_dest);
                    //userdatas = this.adduserdata(userdatas, 'Staff_ID', 3, $E.staff.id);
                    userdatas = this.addDefaultData(userdatas, m_dest);
                    phoneno = this.addprefix(phoneno);

                    userdatas = this.gettransferflags(call.connectionid, userdatas, false);
                    var ud = this.data2jsondata(userdatas);
                    logmsg("cticlient.inittransfer", JSON.stringify(ud));
                    ret = cticlient.inittransfer(call.connectionid, phoneno, ud);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            completeTransfer: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - completeTransfer', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("completeTransfer", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (!call) {
                    call = this.CallInfo.getDialingCall();
                }
                if (call) {
                    if (call.anotherconn) {
                        $SC.CallInfo.releaseaction = {"action": "completetransfer", "actiontime": new Date().valueOf()};
                        ret = cticlient.completetransfer(call.connectionid, call.anotherconn);
                    }
                    /*
            		var call1 = this.CallInfo.getHeldCall();
        			if (call1) {
        				cticlient.completetransfer(call.connectionid, call1.connectionid);
        			}
        			*/
                }
                if (ret == undefined) {
                    ret = true;
                }
                //$SC.CallInfo.releaseaction = {"action": "completetransfer", "actiontime": new Date().valueOf()};
                return ret;
            },

            initConference: function (phoneno, userdatas) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - initConference', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("initConference", "request ingored for not login");
                    return false;
                }

                //$SC.addconsolelog("SoftphoneCore-initConference(" + phoneno + "," + userdatas + ")");
                logmsg("initConference", phoneno , userdatas);

                /*
                if (!userdatas && m_conf.traninternalani) {
                    if (!userdatas && m_conf.traninternalani) {
                        if ($SC.CallInfo.ANI == $SC.dn) {
                            userdatas = m_conf.traninternalani + '=' + $SC.CallInfo.DNIS;
                        } else {
                            userdatas = m_conf.traninternalani + "=" + $SC.CallInfo.ANI;
                        }
                    }
                }
    			 */

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (call) {
                    this.CallInfo.transferflag = 2;
                    this.CallInfo.transferdest = phoneno;
                    m_dest = phoneno;
                    //userdatas = this.userdata2jsonuserdata(userdatas);
                    //userdatas = this.adduserdata(userdatas, 'E_Dest', 3, m_dest);
                    //userdatas = this.adduserdata(userdatas, 'Staff_ID', 3, $E.staff.id);
                    userdatas = this.addDefaultData(userdatas, m_dest);
                    phoneno = this.addprefix(phoneno);

                    if (this.getdatabykey(userdatas, "singlestep") == "1") {
                        //delete userdatas["singlestep"];
                        for (let v in userdatas) {
                            if (v.toLowerCase().indexOf('autocomplete') >= 0 || v.toLowerCase().indexOf('completewhen') >= 0) {
                                delete userdatas[v];
                            }
                        }
                        delete userdatas["singlestep"];
                        logmsg("singlestepconference by singlestep = 1");
                        return cticlient.singlestepconference(call.connectionid, phoneno, this.data2jsondata(userdatas));
                    }

                    userdatas = this.gettransferflags(call.connectionid, userdatas, true);
                    var ud = this.data2jsondata(userdatas);
                    logmsg("cticlient.initconference", phoneno, ud);
                    ret = cticlient.initconference(call.connectionid, phoneno, ud);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            completeConference: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - completeConference', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("completeConference", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (!call) {
                    call = this.CallInfo.getDialingCall();
                }
                if (call) {
                    if (call.anotherconn) {
                        ret = cticlient.completeconference(call.connectionid, call.anotherconn);
                    }
                    /*
            		var call1 = this.CallInfo.getHeldCall();
        			if (call1) {
        				cticlient.completeconference(call.connectionid, call1.connectionid);
        			}
        			*/
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            reconnect: function () {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - reconnect', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("reconnect", "request ingored for not login");
                    return false;
                }

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (!call) {
                    call = this.CallInfo.getDialingCall();
                }
                if (call) {
                    if (call.anotherconn) {
                        ret = cticlient.reconnect(call.connectionid, call.anotherconn);
                    }
                    /*
            		var call1 = this.CallInfo.getHeldCall();
        			if (call1) {
        				cticlient.reconnect(call.connectionid, call1.connectionid);
        			}
        			*/
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            muteTransfer: function (phoneno, userdatas) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - muteTransfer', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("muteTransfer", "request ingored for not login");
                    return false;
                }

                //$SC.addconsolelog("SoftphoneCore-muteTransfer(" + phoneno + "," + userdatas + ")");
                logmsg("muteTransfer", phoneno, userdatas);

                /*
                if (!userdatas && m_conf.traninternalani) {
                    if (!userdatas && m_conf.traninternalani) {
                        if ($SC.CallInfo.ANI == $SC.dn) {
                            userdatas = m_conf.traninternalani + '=' + $SC.CallInfo.DNIS;
                        } else {
                            userdatas = m_conf.traninternalani + "=" + $SC.CallInfo.ANI;
                        }
                    }
                }
    			 */

                var ret;
                var call = this.CallInfo.getActiveCall();
                if (call) {
                    this.CallInfo.transferflag = 3;
                    this.CallInfo.transferdest = phoneno;
                    m_dest = phoneno;
                    //userdatas = this.userdata2jsonuserdata(userdatas);
                    //userdatas = this.adduserdata(userdatas, 'E_Dest', 3, m_dest);
                    //userdatas = this.adduserdata(userdatas, 'Staff_ID', 3, $E.staff.id);
                    userdatas = this.addDefaultData(userdatas, m_dest);
                    phoneno = this.addprefix(phoneno);

                    var ud = this.data2jsondata(userdatas);
                    logmsg("mutetransfer", phoneno, ud);

                    $SC.CallInfo.releaseaction = {"action": "mutetransfer", "actiontime": new Date().valueOf()};
                    ret = cticlient.mutetransfer(call.connectionid, phoneno, ud);
                }
                if (ret == undefined) {
                    ret = true;
                }

                //$SC.CallInfo.releaseaction = {"action": "mutetransfer", "actiontime": new Date().valueOf()};
                return ret;
            },

            addDefaultData: function (userdatas, phoneno) {
                try {
                    userdatas = this.userdata2jsonuserdata(userdatas);
                    //if (userdatas) {
                    //    return userdatas;
                    //}
                    if (this.isinternaldn(phoneno)) {
                        if (m_conf.m_transfer_defaultdata) {
                            var c = m_conf.m_transfer_defaultdata.split('|');
                            for (let i = 0; i < c.length; i++) {
                                switch (c[i].toLowerCase()) {
                                    case 'e_dest':
                                        userdatas = this.adduserdata(userdatas, 'E_Dest', 3, m_dest);
                                        break;
                                    case 'staff_id':
                                        userdatas = this.adduserdata(userdatas, 'Staff_ID', 3, $E.staff.id);
                                        break;
                                    case 'originalani':
                                        userdatas = this.adduserdata(userdatas, 'originalani', 3, $SC.CallInfo.ANI);
                                        break;
                                    case 'orignialdnis':
                                        userdatas = this.adduserdata(userdatas, 'originaldnis', 3, $SC.CallInfo.DNIS);
                                        break;
                                    default:
                                        if (c[i].toLowerCase().startWith("event")) {
                                            var eventfield = c[i].substr(6).toLowerCase();
                                            var e = $SC.CallInfo.m_Event;
                                            if (e.hasOwnProperty(eventfield)) {
                                                var v = e[eventfield];
                                                if (v) {
                                                    userdatas = this.adduserdata(userdatas, c[i], 3, v);
                                                }
                                            }
                                        } else {
                                            var v = $SC.CallInfo.AttachData(c[i]);
                                            if (v) {
                                                userdatas = this.adduserdata(userdatas, c[i], 3, v)
                                            }
                                        }
                                }
                            }
                        }
                        //if (!userdatas && m_conf.traninternalani) {
                        if (m_conf.traninternalani) {
                            if ($SC.CallInfo.ANI == $SC.dn) {
                                userdatas = this.adduserdata(userdatas, m_conf.traninternalani, 3, $SC.CallInfo.DNIS);
                            } else {
                                userdatas = this.adduserdata(userdatas, m_conf.traninternalani, 3, $SC.CallInfo.ANI);
                            }
                        }
                    }
                } catch (err) {

                }
                return userdatas;
            },

            sendDTMF: function (dtmf) {
                if (cticlient.senddtmf) {
                    var ret = cticlient.senddtmf(dtmf);
                    if (ret == undefined) {
                        ret = true;
                    }
                    return ret;
                } else {
                    return false;
                }
            },

            agentReady: function (workmode, options) {
                if (!this.LoginInfo.logined) {
                    //logmsg("agentReady", "request ingored for not login");
                    return false;
                }
                var ret;

                if (m_disableready == 1) {
                    logmsg("agentReady", "request ignored for disabled, reason = " + m_disablereason);
                    if (m_disablereason) {
                        //$F.alert('当前不允许设置就绪状态：' + m_disablereason);
                        $F.alert($SC.lang("common.msg.cannotsetreadyplus", "当前不允许设置就绪状态：") + m_disablereason);
                    } else {
                        $F.alert($SC.lang("common.msg.cannotsetready", "当前不允许设置就绪状态。"));
                    }
                    return false;
                }

                if (options && options.nodelay == 1) {

                //} else if (m_worktype == 'WT-IB' || this.CallInfo.CallState2 != 0) {
                } else if (m_worktype || this.CallInfo.CallState2 != 0) {
                    logmsg("agentReady request ignored for WorkType = " + m_worktype + ", CallState2 = " + this.CallInfo.CallState2);
                    $F.alert($SC.lang("common.msg.nosetreadyoncallorwork", "当前在通话中或者需要电话小结状态。"));
                    return false;
                }

                if (!workmode) {
                    workmode = 2;
                }
                ret = cticlient.agentready(workmode);
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            acw: function () {
                if (!this.LoginInfo.logined) {
                    //logmsg("acw", "request ingored for not login");
                    return false;
                }
                var ret;
                ret = cticlient.acw();
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            agentNotReady: function (workmode, options) {
                if (!this.LoginInfo.logined) {
                    //logmsg("agentNotReady", "request ingored for not login");
                    return false;
                }

                options = options || {};
                //if (options.nodelay!=1 && (m_worktype || this.CallInfo.CallState2 != 0)) {
                if (options.nodelay == 1) {

                } else if (this.CallInfo.CallState2 != 0 || (m_worktype && this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW)) {
                    m_delayagentstate = 'notready';
                    m_delayagentmode = workmode;
                    m_delayreasoncode = '';
                    //$F.alert("切换话务员状态的请求将在通话结束及小结完成后执行");
                    logmsg("agentNotReady delayed for WorkType = " + m_worktype + ", CallState2 = " + this.CallInfo.CallState2);
                    return false;
                    //} else if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_READY) {

                    //} else if (this.agentMode ==  $CTI_CONST.AGENT_WORKMODE.ACW) {

                }

                var ret;
                if (!workmode) {
                    workmode = 3;
                }
                if (workmode == 3 && (m_conf.m_defaultreasoncode != undefined && m_conf.m_defaultreasoncode !== '')) {
                    ret = cticlient.aux(m_conf.m_defaultreasoncode);
                } else {
                    ret = cticlient.agentnotready(workmode);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            agentNotReady2: function (workmode, reasoncode, options) {
                if (!this.LoginInfo.logined) {
                    //logmsg("agentNotReady2", "request ingored for not login");
                    return false;
                }
                options = options || {};
                if (!workmode) {
                    workmode = 3;
                }
                reasoncode = reasoncode || m_conf.m_breakcode;
                //if (options.nodelay!=1 && (m_worktype || this.CallInfo.CallState2 != 0)) {
                if (options.nodelay == 1) {

                } else if (this.CallInfo.CallState2 != 0 || (m_worktype && this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW)) {
                    m_delayagentstate = 'notready';
                    m_delayagentmode = workmode;
                    m_delayreasoncode = reasoncode;
                    //$F.alert("切换话务员状态的请求将在通话结束及小结完成后执行");
                    logmsg("agentNotReady(" + reasoncode + ") delayed for WorkType = " + m_worktype + ", CallState2 = " + this.CallInfo.CallState2);
                    return false;
                }
                var ret;
                if (reasoncode) {
                    ret = cticlient.aux(reasoncode);
                } else {
                    ret = cticlient.agentnotready(workmode);
                }
                if (ret == undefined) {
                    ret = true;
                }
                return ret;
            },

            idleagents: function(params, callback) {
                if (cticlient.idleagents) {
                    return cticlient.idleagents(params, callback);
                } else {
                    return false;
                }
            },

            //视频功能

            //生成坐席视频工作台
            drawVideo: function(params, callback) {
                if (cticlient.drawVideo) {
                    return cticlient.drawVideo(params, callback);
                } else {
                    return false;
                }
            },

            //切换麦克风关闭/打开
            toggleMicrophone: function(params, callback) {
                if (cticlient.toggleMicrophone) {
                    return cticlient.toggleMicrophone(params, callback);
                } else {
                    return false;
                }
            },

            //切换摄像头关闭/打开
            toggleCamera: function(params, callback) {
                if (cticlient.toggleCamera) {
                    return cticlient.toggleCamera(params, callback);
                } else {
                    return false;
                }
            },

            //获取流程树
            getVideoFlowTree: function(params, callback) {
                if (cticlient.getVideoFlowTree) {
                    return cticlient.getVideoFlowTree(params, callback);
                } else {
                    return false;
                }
            },

            //获取产品流程
            getVideoFlowProcess: function(params, callback) {
                if (cticlient.getVideoFlowProcess) {
                    return cticlient.getVideoFlowProcess(params, callback);
                } else {
                    return false;
                }
            },

            //获取会议成员（成员列表）
            getRoomMemberList: function(params, callback) {
                if (cticlient.getRoomMemberList) {
                    return cticlient.getRoomMemberList(params, callback);
                } else {
                    return false;
                }
            },

            //获取会议成员（客户列表）
            getRoomCustomerList: function(params, callback) {
                if (cticlient.getRoomCustomerList) {
                    return cticlient.getRoomCustomerList(params, callback);
                } else {
                    return false;
                }
            },

            //桌面共享
            shareDesktop: function(params, callback) {
                if (cticlient.shareDesktop) {
                    return cticlient.shareDesktop(params, callback);
                } else {
                    return false;
                }
            },

            //电子白板
            eleWhiteBoard: function(params, callback) {
                if (cticlient.eleWhiteBoard) {
                    return cticlient.eleWhiteBoard(params, callback);
                } else {
                    return false;
                }
            },

            //
            implementSLProcess: function(params, callback) {
                if (cticlient.implementSLProcess) {
                    return cticlient.implementSLProcess(params, callback);
                } else {
                    return false;
                }
            },

            toReportAgent: function () {
                /*
            	if (m_conf.m_report_always == 1 && m_conf.m_report_dest) {
            		this.initConference(m_conf.m_report_dest, this.replaceruntimevalues(m_conf.m_report_userdatas));
            	}
*/
                var ireport = 0;
                if (m_conf.m_report_dest) {
                    switch (m_conf.m_report_always) {
                        case 0:
                            if (m_conf.m_report_keytoreport && $SC.CallInfo.attachdata(m_conf.m_report_keytoreport) == '0') {
                                ireport = 1;
                            }
                            break;
                        case 1:
                            ireport = 1;
                            break;
                        case 2:
                            if ($SC.isinternaldn($SC.CallInfo.ANI)) {
                                ireport = -1;
                            } else if ($SC.CallInfo.attachdata('e_dest')) {
                                ireport = -1;
                            } else {
                                ireport = 1;
                            }
                            break;
                        case 3:
                            if ($SC.CallInfo.attachdata(m_conf.m_report_keytoreport) == '1') {
                                ireport = -1;
                            } else {
                                ireport = 1;
                            }
                            break;
                        default:
                            ireport = 0;
                    }
                    if (ireport > 0) {
                        this.initConference(m_conf.m_report_dest, this.replaceruntimevalues(m_conf.m_report_userdatas));
                    }
                }
            },

            doautoanswer: function (nodelay) {
                var t = this;
                //if (t.m_conf.m_AutoAnswerdelay > 0) {
                if (!nodelay && m_conf.m_AutoAnswerDelay > 0) {
                    setTimeout(function () {
                        if (t.CallInfo.CallState2 == 1) {
                            t.answerCall();
                        }
                        //}, t.m_conf.m_AutoAnswerdelay);
                    }, m_conf.m_AutoAnswerDelay);
                } else {
                    if (t.CallInfo.CallState2 == 1) {
                        t.answerCall();
                    }
                }
            },

            replaceruntimevalues: function (s) {
                if (s) {
                    var s1 = s.replace(/\[agentid\]/ig, this.agentId);
                    s1 = s1.replace(/\[extension\]/ig, this.dn);
                    s1 = s1.replace(/\[staff_id\]/ig, $E.staff.id);
                    s1 = s1.replace(/\[event_guid\]/ig, this.CallInfo.Event_GUID);
                    s1 = s1.replace(/\[recording_guid\]/ig, this.Recording_GUID);
                    s1 = s1.replace(/\[calltype\]/ig, this.CallInfo.CallType);
                    return s1;
                } else {
                    return '';
                }
            },

            isinternaldn: function (s) {
                if (m_conf.m_dnlist) {
                    var reg = new RegExp(m_conf.m_dnlist);
                    return reg.test(s);
                } else {
                    return true;
                }
            },

            addcalloutdata: function(dest, userdatas) {
                if (m_conf.m_calloutdata) {
                    if (!userdatas) {
                        userdatas = {};
                    }
                    if (this.isinternaldn(dest)) {

                    } else {
                        for (let x in m_conf.m_calloutdata) {
                            if (userdatas[x]) {

                            } else {
                                userdatas[x] = m_conf.m_calloutdata[x];
                            }
                        }
                    }
                }
                return userdatas;
            },

            addprefix: function (dest) {
                if (m_conf.m_areacode && dest.length == 11) {
                    var regx = /^1[3456789]\d{9}$/;
                    if (regx.test(dest)) {
                        var r = this.executeselectsql('softphone.mobilearea.query.v201610', [$E.staff.epidSql, dest]);
                        if (r && r.code > 0) {
                            if (r.value && r.value[0].count > 0) {
                                if (m_conf.m_areacode == r.value[0].fields[0][0]) {
                                } else {
                                    dest = '0' + dest;
                                }
                            } else {
                                dest = '0' + dest;
                            }
                        }
                    }
                }

                if (this.autoPrefix && this.autoPrefix != m_conf.m_autoprefix) {
                    logmsg('SoftphoneCore -- addprefix, autoprefix changed from ' + m_conf.m_autoprefix + ' to ' + this.autoPrefix);
                    m_conf.m_autoprefix = this.autoPrefix;
                }
                if (m_conf.m_autoprefix) {
                    if (this.isinternaldn(dest)) {
                        return dest;
                    } else {
                        if (m_conf.m_autoprefix == '9' && (dest.substr(0, m_conf.m_autoprefix.length) == m_conf.m_autoprefix)) {
                            if (dest.length < 8) {
                                if (dest.match('99[56]')) {
                                    return dest;
                                } else {
                                    return m_conf.m_autoprefix + dest;
                                }
                            } else if (dest.length < 15) {
                                return dest;
                            } else {
                                return m_conf.m_autoprefix + dest;
                            }
                        } else {
                            return m_conf.m_autoprefix + dest;
                        }
                    }
                } else {
                    return dest;
                }
            },

            removeprefix: function (phoneno) {
                if (m_conf.m_removeprefix) {
                    try {
                        if (m_conf.m_removeprefix == 4) {
                            //if (phoneno.length > 8) {
                                phoneno = phoneno.replace(m_conf.m_removeprefixlist, "");
                            //}
                        } else {
                            for (let ii = 0; ii < m_conf.m_removeprefixlist.length; ii++) {
                                if (phoneno.substr(0, m_conf.m_removeprefixlist[ii].length) == m_conf.m_removeprefixlist[ii]) {
                                    return phoneno.substr(m_conf.m_removeprefixlist[ii].length);
                                }
                            }
                        }
                    } catch (e) {

                    }
                }
                return phoneno;
            },

            mute: function () {
                if ($.isFunction(cticlient.mute)) {
                    return cticlient.mute();
                } else {
                    logmsg("softphone.core: unsupported request mute");
                }
            },

            unmute: function () {
                if ($.isFunction(cticlient.unmute)) {
                    return cticlient.unmute();
                } else {
                    logmsg("softphone.core: unsupported request unmute");
                }
            },

            manyidu: function () {
                if (m_conf.m_myd_dest) {
                    this.muteTransfer(m_conf.m_myd_dest, this.replaceruntimevalues(m_conf.m_myd_userdatas));
                }
            },

            addmonitorcallback: function(callback, monitortype, options) {
                logmsg("addmonitorcalback", monitortype, $.isFunction(callback));
                if ($SC._timer_monitor) {
                    clearTimeout(($SC._timer_monitor));
                    $SC._timer_monitor = 0;
                    if ($SC._callback_monitor) {
                        $SC._callback_monitor({code: 3, "reason": "new request"});
                        $SC._callback_monitor = undefined;
                    }
                }
                if (callback && $.isFunction(callback)) {
                    $SC._callback_monitor = callback;
                    $SC._timer_monitor = setTimeout(function(){
                        //callback({"code": 2, "reason": "timed out"});
                        $SC.endmonitorcallback({"code": 2, "reason": "timed out"})
                    }, 2000);
                }
            },

            endmonitorcallback: function(data, callback, monitortype, options) {
                logmsg("endmonitorcalback", monitortype,$.isFunction($SC._callback_monitor), data);
                if (callback && $.isFunction(callback)) {
                    callback(data);
                }
                if ($SC._timer_monitor) {
                    clearTimeout($SC._timer_monitor);
                    $SC._timer_monitor = 0;
                }
                if ($SC._callback_monitor) {
                    if (!callback) {
                        $SC._callback_monitor(data);
                    }
                    $SC._callback_monitor = undefined;
                }
            },

            //监听
            listen: function (dn, agentId, callback) {
                var ret = false;
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - listen', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("listen", "request ignored for not login");
                    $SC.endmonitorcallback({"code": 9, "reason": "fail"}, callback);
                    return ret;
                }
                try {
                    ret = cticlient.listen(dn, agentId, callback);
                    this.addmonitorcallback(callback,"listen");
                } catch (err) {
                    logmsg('SoftphoneCore - listen: ' + err);
                    $SC.endmonitorcallback({"code": 9, "reason": "fail"}, callback);
                    return ret;
                }
            },

            //强插
            bargeIn: function (dn, agentId, callback) {
                var ret = false;
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - bargeIn', 'request ingored for not login', undefined, 'cticall');
                    //logmsg("bargeIn", "request ignored for not login");
                    $SC.endmonitorcallback({"code": 9, "reason": "fail"}, callback);
                    return ret;
                }
                try {
                    ret = cticlient.bargein(dn, agentId, callback);
                    this.addmonitorcallback(callback, "bargein");
                    return ret;
                } catch (err) {
                    logmsg('SoftphoneCore - bargeIn: ' + err);
                    $SC.endmonitorcallback({"code": 9, "reason": "fail"}, callback);
                    return ret;
                }
            },

            takeOver: function (dn, agentId, callback) {
                return this.intercept(dn, agentId, callback);
            },

            //接管
            intercept: function (dn, agentId, callback) {
                var ret = false;
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - intercept', 'request ingored for not login', undefined, 'cticall');
                    return ret;
                }
                try {
                    ret = cticlient.intercept(dn, agentId, callback);
                    this.addmonitorcallback(callback, "intercept");
                    return ret;
                } catch (err) {
                    logmsg('SoftphoneCore - intercept: ' + err);
                    return ret;
                }
            },

            //密语/教练
            coach: function (dn, agentId, callback) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - coach', 'request ingored for not login', undefined, 'cticall');
                    return false;
                }
                try {
                    return cticlient.coach(dn, agentId, callback);
                } catch (err) {
                    logmsg('SoftphoneCore - coach: ' + err);
                    return false;
                }
            },

            forceHangup: function (dn, agentId, callback) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - foreceHangup', 'request ingored for not login', undefined, 'cticall');
                    return false;
                }
                try {
                    return cticlient.forcehangup(dn, agentId, callback);
                } catch (err) {
                    logmsg('SoftphoneCore - forceHangup: ' + err);
                    return false;
                }
            },

            forceDisconnectAgentByDN: function(dn, agentId, callback) {
                var ret;
                if ($.isFunction(cticlient.forceDisconnectAgentByDN)) {
                    ret = cticlient.forceDisconnectAgentByDN(dn, agentId, callback);
                    this.addmonitorcallback(callback, "forceDisconnect");
                } else {
                    ret = this.forceHangup(dn, agentId, callback);
                    this.addmonitorcallback(callback, "forcehangup");
                }
                return ret;
            },

            forceAgentLogout: function (dn, agentId, callback) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - forceAgentLogout', 'request ingored for not login', undefined, 'cticall');
                    return false;
                }
                try {
                    return cticlient.forceagentlogout(dn, agentId, callback);
                } catch (err) {
                    logmsg('SoftphoneCore - forceAgentLogout: ' + err);
                    return false;
                }
            },

            forceAgentReady: function (dn, agentId, callback) {
                if (!this.LoginInfo.logined) {
                    //this.addlog('SoftphoneCore - forceAgentReady', 'request ingored for not login', undefined, 'cticall');
                    return false;
                }
                try {
                    return cticlient.forceagentready(dn, agentId, callback);
                } catch (err) {
                    logmsg('SoftphoneCore - forceAgentReady: ' + err);
                    return false;
                }
            },

            forceAgentNotReady: function (dn, agentId, callback) {
                if (!this.LoginInfo.logined) {
                    logmsg('SoftphoneCore - forceAgentNotReady', 'request ingored for not login', undefined, 'cticall');
                    return false;
                }
                try {
                    return cticlient.forceagentnotready(dn, agentId, callback);
                } catch (err) {
                    logmsg('SoftphoneCore - forceAgentNotReady: ' + err);
                    return false;
                }
            },

            notifyWorkStart: function (WorkType) {
                //if (!WorkType) {
                //	this.WorkType = 'WT-IB'
                //}
                logmsg('SoftphoneCore -- notifyWorkStart(' + WorkType + ')');
                m_worktype = WorkType;
                //if (this.m_conf.m_AutoAnswer == 0 && this.CallInfo.CallState2 == 1) {
                if (m_conf.m_AutoAnswer == 0 && this.CallInfo.CallState2 == 1) {
                    this.doautoanswer(true);
                }
            },

            notifyWorkEnd: function () {
                var sc = this;

                if ($SC._timer_autoworkend) {
                    clearTimeout($SC._timer_autoworkend);
                    $SC._timer_autoworkend = 0;
                }

                logmsg('SoftphoneCore -- notifyWorkEnd()');
                if (m_conf.m_AutoReleaseCall == 1) {
                    if (sc.CallInfo.CallState2 != 0) {
                        sc.releaseCall();
                    }
                }
                var m_wtype = m_worktype;	//sc.m_worktype;
                /*
				if (!m_wtype) {
					if (sc.CallInfo.CallType == $CTI_CONST.CALL_TYPE.CT_OUTBOUND) {
						m_wtype = "WT-OB"
					} else {
						m_wtype = "WT-IB"
					}
				}
				 */
                var m_incall = false;
                var m_count = 0;
                if (sc.CallInfo.CallState2 != 0) {
                    m_incall = true;
                }
                /*
            	var t = setTimeout(function(){
            		//sc.CallInfo.afterWorkEnd(sc.m_worktype)
            		sc.CallInfo.afterWorkEnd(m_wtype);
            	}, 500);
            	*/
                if (!m_incall) {
                    if (this.agentState == $CTI_CONST.AGENT_STATE.EAS_NOTREADY && this.agentMode == $CTI_CONST.AGENT_WORKMODE.ACW) {
                        //sc.m_worktype = '';
                        m_worktype = '';
                        logmsg('SoftphoneCore -- notifyWorkEnd, afterWorkEnd, m_count = ' + m_count + ', m_worktype = ' + m_worktype);
                        sc.CallInfo.afterWorkEnd(m_wtype);
                        m_count = -1;
                    }
                }
                if (m_count == 0) {
                    m_tmp_worktype = m_worktype;
                    var t = setInterval(function () {
                        m_count++;
                        if (m_count >= 4) {
                            clearInterval(t);
                            logmsg('SoftphoneCore -- notifyWorkEnd, afterWorkEnd, m_count = ' + m_count);
                            sc.CallInfo.afterWorkEnd(m_wtype);
                        } else {
                            if (m_incall) {
                                if (sc.CallInfo.CallState2 == 0) {
                                    m_incall = false;
                                }
                            } else {
                                clearInterval(t);
                                logmsg('SoftphoneCore -- notifyWorkEnd, afterWorkEnd, m_count = ' + m_count);
                                sc.CallInfo.afterWorkEnd(m_wtype);
                            }
                        }
                    }, 500);
                }
                //sc.m_worktype = '';
                m_worktype = '';
            },

            data2jsondata: function(data) {
                if (data) {
                    var t_datas;
                    var datas = data;
                    if (typeof(datas) === "string") {
                        datas = JSON.parse(datas);
                    }
                    t_datas = {};
                    for(let x in datas) {
                        if (typeof(datas[x] === "object")) {
                            if (datas[x].hasOwnProperty("type") && datas[x].hasOwnProperty("value")) {
                                t_datas[x] = datas[x].value;
                            } else {
                                t_datas[x] = datas[x];
                            }
                        } else {
                            t_datas[x] = datas[x];
                        }
                    }
                    return t_datas;
                }
            },

            userdata2jsonuserdata: function (userdatas) {
                //userdatas: JSON Object, JSON string, '|' and '=' splitted key-value string
                if (userdatas) {
                    if (typeof (userdatas) == 'object') {
                        return userdatas;
                    }
                    try {
                        var t_datas = JSON.parse(userdatas);
                        //return userdatas;
                        return t_datas;
                    } catch (err) {
                        var iudskeys = userdatas.toLowerCase().indexOf('|userdatakeys=');
                        //var udskeys = [];
                        if (iudskeys >= 0) {
                            //var u1 = userdatas.substr(iudskeys + '|userdatakeys='.length)
                            //udskeys = u1.split('|');
                            userdatas = userdatas.substr(0, iudskeys);
                        }
                        var t_data = {};
                        var uud = '';
                        var iuud = ('|' + userdatas.toLowerCase()).indexOf('|raw_data=');
                        if (iuud >= 0) {
                            uud = userdatas.substr(iuud + '|raw_data='.length - 1);
                        } else {
                            var iuud = ('|' + userdatas.toLowerCase()).indexOf('|rawdata=');
                            if (iuud >= 0) {
                                uud = userdatas.substr(iuud + '|rawdata='.length - 1);
                            } else {
                                iuud = ('|' + userdatas.toLowerCase()).indexOf('|uu_data=');
                                if (iuud >= 0) {
                                    uud = userdatas.substr(iuud + '|uu_data='.length - 1);
                                }
                            }
                        }
                        if (iuud >= 0) {
                            userdatas = userdatas.substr(0, iuud - 1);
                        }

                        if (userdatas) {
                            var i = userdatas.lastIndexOf("=");
                            var s2 = userdatas;
                            if (i>0) {
                                s2 = s2.substr(i+2);
                                userdatas = userdatas.substr(0, i+2);
                            }
                            var t_data1 = userdatas.split("\|");
                            //for (let onedata in t_data1){
                            for (let i = 0; i < t_data1.length; i++) {
                                var onedata = t_data1[i];
                                var n = onedata.indexOf("=");
                                if (n >= 0) {
                                    if (i=== t_data1.length-1) {
                                        t_data[onedata.substr(0, n)] = onedata.substr(n + 1) + s2;
                                    } else {
                                        t_data[onedata.substr(0, n)] = onedata.substr(n + 1);
                                    }
                                }
                            }
                        }
                        if (uud) {
                            t_data.uu_data = uud;
                        }
                        //return JSON.stringify(t_data);
                        return t_data;
                    }
                }
            },

            adduserdata: function (userdatas, key, type, value) {
                if (!userdatas) {
                    //userdatas = JSON.stringify({type : 5, value : {}});
                    userdatas = JSON.stringify({});
                }
                if (typeof (userdatas) == 'string') {
                    try {
                        var t_data = JSON.parse(userdatas);
                        t_data[key] = {
                            type: type,
                            value: value
                        };
                        return JSON.stringify(t_data);
                    } catch (err) {

                    }
                } else {
                    userdatas[key] = {
                        type: type,
                        value: value
                    };
                    return JSON.stringify(userdatas);
                }
            },

            getdatabykey: function (datas, key) {
                var d = datas;
                try {
                    if (typeof (d) == 'string') {
                        d = JSON.parse(d);
                    }
                    if (d) {
                        for (let vkey in d) {
                            if (vkey.toLowerCase() == key.toLowerCase()) {
                                if (d[vkey].hasOwnProperty('value')) {
                                    return d[vkey].value;
                                } else {
                                    return d[vkey];
                                }

                            }
                        }
                    }
                } catch (err) {

                }
            },

            removedatabykey: function (datas, key) {
                var d = datas;
                try {
                    if (typeof (d) == 'string') {
                        d = JSON.parse(d);
                    }
                    if (d) {
                        for (let vkey in d) {
                            if (vkey.toLowerCase() == key.toLowerCase()) {
                                delete d[vkey];
                            }
                        }
                        return JSON.stringify(d);
                    }
                } catch (err) {

                }
            },
            /*
		    userdata2jsonstr : function(userdatas) {
		    	//userdatas: JSON Object, JSON string, '|' and '=' splitted key-value string
		    	if (userdatas) {
		    		if (typeof(userdatas) == 'object') {
		    			return JSON.stringify(userdatas);
		    		}
			    	try{
			    		var t_datas = JSON.parse(userdatas);
				    	return userdatas;
			    	} catch(err) {
		    			var t_data1 = userdatas.split("\|");
		    			var t_data = {};
		    			//for (let onedata in t_data1){
		    			for (let i=0; i < t_data1.length; i++) {
		    				var onedata = t_data1[i];
		    				var n = onedata.indexOf("=");
		    				if (n >= 0) {
		    					t_data[onedata.substr(0, n)] = {"value" : onedata.substr(n+1), "type" : 3};
		    				}
		    			}
		    			return JSON.stringify(t_data);
			    	}
		    	}
		    },
*/
            QuitSoftphone: function () {
                if (this.LoginInfo.logined) {
                    this.agentLogout();
                }

                this.doquitsoftphone();

                if ($E.staff && $E.staff.id) {
                    if ($E.ver.indexOf('Softphone') > -1) {
                        setTimeout(function () {
                            if ($E.staff && $E.staff.id) {
                                $E.logout();
                            }
                        }, 500);
                    }
                }
            },

            doquitsoftphone : function() {
                this.addconsolelog("doquitsoftphone()");
                try {
                    if (this.agentState >=2) {
                        this.addconsolelog("fake EVT_AGENTLOGOUT in doquitsoftphone()");
                        var evt = {};
                        evt.event = {type: 1, value: $CTI_CONST.CTI_MSG.EVT_AGENTLOGOUT};
                        evt.eventdesc = {type: 3, value: "EVT_AGENTLOGOUT"};
                        this.onCTIEvent(evt);
                    }
                } catch (err) {
                    this.addconsolelog("SoftphoneCore--doquitsoftphone, fail with err :" + JSON.stringify(err));
                }
                this.addconsolelog("doquitsoftphone() done");
            },

            commonCall: function (callName, callParas, callback) {
                //this.addlog('SoftphoneCore - commonCall(' + callName + ', ' + callParas + ')');
                logmsg("commonCall", callName, callParas);
                var ret;
                var ctitypechanged = false;
                var basync = false;
                switch (callName.toLowerCase()) {
                    case "setprofile":
                        var profile = callParas.split("=");
                        if (profile[0].toLowerCase() == "ctitype") {
                            if (ctitype != profile[1]) {
                                ctitypechanged = true;
                                //this.addlog("SoftphoneCore - ctiType changed from " + ctitype + " to " + profile[1]);
                                logmsg("ctiType changed from ", ctitype, " to ", profile[1]);
                                ctitype = profile[1];
                                this.ctiType = ctitype;
                                return this.initSoftphone(callback, callback, {ctiType: ctitype, resetctitype: true});
                            }
                        }
                        break;
                    case 'setevent':
                        $SC.CallInfo.setEvent(callParas);
                        if ($.isFunction(callback)) {
                            callback();
                        }
                        break;
                    case 'getevent':
                        ret = $SC.CallInfo.getEvent(callParas);
                        if ($.isFunction(callback)) {
                            callback(ret);
                        } else {
                            return ret;
                        }
                        break;
                    case 'getinivalue':
                        if (callParas == "[CTI]AgentID") {
                            ret = this.agentid;
                        } else if (callParas == "[CTI]Extension") {
                            ret = this.dn;
                        } else {
                            var section = callParas.substring(callParas.indexOf('[') + 1, callParas.indexOf(']'));
                            var key = callParas.substring(callParas.indexOf(']') + 1, callParas.length);
                            //ret = this._getconfig(section, key, this.agentId, this.dn);
                            ret = this._getconfig(section, key, $SC.staff.agentId || this.agentId, $SC.staff.extension || this.dn);
                        }
                        break;
                    case 'removeuserdata':
                        var datas = callParas.split('|');
                        for (let i = 0; i < datas.length; i++) {
                            $SC.CallInfo.removedata(datas[i]);
                        }
                        break;
                    case 'button.click':
                        var key1 = callParas.toLowerCase().substring(0, 'notreadycode_'.length);
                        var key2 = Number(callParas.toLowerCase().substring('notreadycode_'.length));
                        if (key1 == 'notreadycode_' && key2 >= 0) {
                            ret = this.agentNotReady2(3, key2)
                        } else if (callParas.toLowerCase() == "break") {
                            ret = this.agentNotReady2(3);
                        } else {
                            //this.addlog('SoftphoneCore - commonCall, unsupported request type ' + callParas + ', ' + callParas);
                            logmsg("commonCall", "unsupported request type", callParas);
                        }
                        break;
                    case "setrecord":
                    case "queryextra":
                        var param = {params: callParas};
                        var scallname = callName.toLowerCase();
                        if (scallname == "setrecord") {
                            param.callname = scallname;
                            scallname = "queryextra";
                        }
                        if (typeof (callParas) == 'string') {
                            var callp = callParas;
                            var i = ('|' + callp).toLowerCase().indexOf('|callname=');
                            var j = -1;
                            if (i >= 0) {
                                j = (callp.toLowerCase() + '|').indexOf('|', i);
                                param.callname = callp.substr(i + 'callname='.length, j - i - 'callname='.length);
                                callp = callp.substr(0, i) + callp.substr(j + 1);
                            }
                            i = ('|' + callp).toLowerCase().indexOf('|dest=');
                            if (i >= 0) {
                                j = (callp.toLowerCase() + '|').indexOf('|', i);
                                param.dest = callp.substr(i + 'dest='.length, j - i - 'dest='.length);
                                callp = callp.substr(0, i) + callp.substr(j + 1);
                            }
                            param.params = callp;
                        }
                        this.querycall(scallname, param, callback);
                        break;
                    case "conferenceivr":
                        if (typeof (callParas) == 'string') {
                            if (('!' + callParas.toLowerCase()).indexOf('|callname=') < 0) {
                                callParas = 'callname=conferenceivr|' + callParas
                            }
                        } else {
                            callParas.callname = 'conferenceivr';
                        }
                        return this.commonCall('queryextra', callParas);
                        break;
                    case "getagentqueues":
                        basync = true;
                        if (cticlient && $.isFunction(cticlient.getagentqueues)) {
                            cticlient.getagentqueues(callParas, callback);
                        } else {
                            basync = false;
                            ret = []
                        }
                        break;
                    case "setagentqueue":
                        if (cticlient && $.isFunction(cticlient.setagentqueue)) {
                            ret = cticlient.setagentqueue(callParas)
                        } else {
                            ret = false;
                        }
                        break;
                    case "disableagentready":
                        m_disableready = 0;
                        m_disablereason = '';
                        var v1 = callParas.split('|');
                        for (let i = 0; i < v1.length; i++) {
                            var j = v1[i].indexOf('=');
                            if (j >= 0) {
                                if (v1[i].substr(0, j).toLowerCase() == 'disable') {
                                    m_disableready = parseInt(v1[i].substr(j + 1));
                                } else if (v1[i].substr(0, j).toLowerCase() == 'disablereason') {
                                    m_disablereason = v1[i].substr(j + 1);
                                }
                            }
                        }
                        break;
                    case "cticlient.setconfig":
                        if (cticlient.setconfig) {
                            if (typeof(callParas) === "string") {
                                callParas = JSON.parse(callParas);
                            }
                            ret = cticlient.setconfig(callParas);
                        } else {
                            //this.addlog("SoftphneCore - commonCall, cticlient does not support setconfig");
                            logmsg("commonCall", "cticlient does not support setconfig");
                        }
                    default:
                        if (callName.substr(0, 10) === "cticlient.") {
                            return cticlient.commoncall(callName.substr(10), callParas, callback);
                        }
                        if (callName === "getsc") {
                            if (this[callParas]) {
                                return this[callParas];
                            }
                        }
                        //this.addlog('SoftphoneCore - commonCall, unsupported request type ' + callName);
                        logmsg("commonCall", "unsupported request type", callName, callParas);
                }
                if (!basync && $.isFunction(callback)) {
                    callback(ret);
                } else {
                    return ret;
                }
            },

            //datas: JSON, maybe with ServerTime, if need getservertime from local, then use ServerTime
            getservertime: function (datas) {
                if (datas && datas.servertime) {
                    return datas.servertime.value;
                }
                return $F.getDbTime();
            },

            setRecordInfo: function (record) {
                if (record) {
                    $SC.addconsolelog("SetRecordInfo: " + JSON.stringify(record));
                    var norecord_guid = false;
                    if (this.CallInfo.m_Event && this.CallInfo.m_Event.event_guid) {
                        if (!this.CallInfo.m_Event.record_guid) {
                            norecord_guid = true;
                        }
                        this.CallInfo.m_Event.record_guid = record.recording_guid;
                        this.Recording_GUID = record.recording_guid;
                        this.RecordingFlag = record.recording_state;
                        this.Recording_File = record.recording_file;
                        if (norecord_guid && this.CallInfo.CallState2 == 0) { // && !m_worktype) {
                            logmsg("save event for record");
                            $SC.CallInfo.saveEvent(2);
                        }
                    }

                    if (record.recording_state > 0) {
                        this.fireSCTIEvent('1077');
                    } else {
                        this.RecordingFlag = record.recording_state;
                    }
                } else {
                    if (this.RecordingFlag > 0) {
                        this.Recording_GUID = '';
                        this.RecordingFlag = 0;
                        this.Recording_File = '';

                        this.fireSCTIEvent('1078');
                    }
                }
            },

            executeupdatesql: function (sqlkey, params) {
                var iseq = ++m_execseq;
                var duration = 0;
                var starttime = new Date().valueOf();
                //this.addlog('SoftphoneCore - executeupdatesql', 'execupdate(' + iseq + ')' + ': ' + sqlkey + ' ' + params, undefined, 'executeupdatesql');
                logmsg("executeupdatesql", "execupdate(" + iseq + ")", sqlkey, params);
                var r = $E.getActiveProject().commonUpdateSync(sqlkey, params);
                duration = new Date().valueOf() - starttime;
                //this.addlog('SoftphoneCore - executeupdatesql', 'execupdate(' + iseq + ').rows = ' + r + ", duration = " + duration, undefined, 'executeupdatesql');
                logmsg("executeupdatesql", "executeupdate(" + iseq + ").rows = " + r, "duration = " + duration);
                return r;
            },

            executeselectsql: function (sqlkey, params) {
                var iseq = ++m_execseq;
                var iret = -1;
                var duration = 0;
                var starttime = new Date().valueOf();
                //this.addlog('SoftphoneCore - executeselectsql', 'execselect(' + iseq + ')' + ': ' + sqlkey + ' ' + params, undefined, 'executeselectsql');
                logmsg("executeselectsql", "execselect(" + iseq + ")", sqlkey, params);
                var r = $E.getActiveProject().commonQuerySync(sqlkey, params);
                if (r && r.code) {
                    iret = r.code;
                }
                duration = new Date().valueOf() - starttime;
                //this.addlog('SoftphoneCore - executeselectsql', 'execselect(' + iseq + ').rows = ' + iret + ", duration = " + duration, undefined, 'executeselectsql');
                logmsg("executeselectsql", "execselect(" + iseq + ").rows = " + iret, "duration = " + duration);
                return r;
            },

            executeupdate: function (sqlkey, params, callback, executefirst) {
                var t = this;
                var duration = 0;

                if (executefirst) {
                    if (m_sqlarr.length > 0) {
                        var req = m_sqlarr[0];
                        if (req.runflag > 0) {
                            return;
                        }
                        var iseq = req.iseq;
                        var basync = req.async;
                        //$SC.addconsolelog("SoftphoneCore - executeupdate" + ", from stack fetch first " + req.iseq);
                        logmsg("executeupdate", "from stack fetch first", req.iseq);
                    }
                } else {
                    var iseq = ++m_execseq;
                    var basync = $.isFunction(callback) || callback === 'async:true' || callback === 'async: true' || callback === true;
                    //t.addlog('SoftphoneCore - executeupdate', 'execupdate(' + iseq + ')' + (basync ? 'a' : '') + ': ' + sqlkey + ' ' + params, undefined, 'executeupdatesql');
                    logmsg("executeupdate", "execupdate(" + iseq + ")" + (basync ? "a": ""), sqlkey, params);
                    var req = {
                        'iseq': iseq,
                        'sqlkey': sqlkey,
                        'params': params,
                        'callback': callback,
                        'reqtime': new Date(),
                        'starttime': null,
                        'endtime': null,
                        'async': basync,
                        'runflag': 0
                    };
                    if (basync) {
                        if (m_sqlarr.length > 0) {
                            if (m_sqlarr[0].runflag == 1) {
                                duration = new Date().valueOf() - m_sqlarr[0].starttime.valueOf()
                                if (Math.abs(duration) > 60000) {
                                    //t.addlog('SoftphoneCore - executeupdate', 'drop ' + iseq + ' from request stack for timed out duration ' + duration);
                                    logmsg("executeupdate", "drop " + iseq + " from request stack for timed out duration " + duration);
                                    if (m_sqlarr[0].dataserviceTimer) {
                                        //clearTimeout(m_sqlarr[0].dataserviceTimer);
                                        $SC.stopTimer(m_sqlarr[0].dataserviceTimer)
                                    }
                                    m_sqlarr.shift();
                                }
                            }
                        }
                        m_sqlarr.push(req);
                        if (m_sqlarr.length > 1) {
                            //t.addlog('SoftphoneCore - executeupdate', 'executedate(' + iseq + ') pushed call request stack, stack length = ' + m_sqlarr.length + ', first is ' + m_sqlarr[0].iseq);
                            logmsg("executeupdate", "execupdate(" + iseq + ") pushed call request stack, stacck length = " + m_sqlarr.length + ", first is " + m_sqlarr[0].iseq);
                            return;
                        }
                        req = m_sqlarr[0];
                    }
                }

                req.runflag = 1;
                req.starttime = new Date();
                var proj = $E.getActiveProject();
                var result = 0;

                if (basync) {
                    //req.dataserviceTimer = setTimeout(function() {
                    req.dataserviceTimer = $SC.startTimer(6000,1,0,"softphone.core.sqlarr." + req.iseq, function() {
                        if (m_sqlarr.length > 0) {
                            //t.addlog('SoftphoneCore - executeupdate', 'drop ' + m_sqlarr[0].iseq + ' from request stack for more than 60s by Timer');
                            logmsg("executeupdate", "drop " + m_sqlarr[0].iseq + " from request stack for more than 60s by Timer");
                            m_sqlarr.shift();
                            if (m_sqlarr.length > 0) {
                                if (m_sqlarr.length > 0) {
                                    //t.addlog('SoftphoneCore - executeupdate', 'to execute stacked request by timedout'  + ', stack length = ' + m_sqlarr.length + ', first is  ' + m_sqlarr[0].iseq);
                                    logmsg("executeupdate", "to execute stacked request by timed out", "stack length = " + m_sqlarr.length + ", first is " + m_sqlarr[0].iseq);
                                    t.executeupdate(undefined, undefined, undefined, true);
                                }
                            }
                        }
                    });
                    //, 6000);
                    //req.dataserviceTimer = dataserviceTimer;
                }
                $F.dataService('SystemDo1', {
                    async: basync,
                    //data : $F.sqlbean(sqlkey, proj.token, params),
                    data: $F.sqlbean(req.sqlkey, proj.token, req.params),
                    digest: proj.digest,
                    success: function (data) {
                        duration = 0;
                        if (req.starttime) {
                            duration = new Date().valueOf() - req.starttime.valueOf();
                        }
                        //t.addlog('SoftphoneCore - executeupdate', 'execupdate(' + iseq + ').rows = ' + data.code + ", duration = " + duration, undefined, 'executeupdatesql');
                        logmsg("executeupdate", "execupdate(" + iseq + ").rows = " + data.code, "duration = " + duration);
                        if (req.async) {
                            if (req.dataserviceTimer) {
                                //clearTimeout(req.dataserviceTimer);
                                //req.dataserviceTimer = 0;
                                $SC.stopTimer(req.dataserviceTimer);
                                req.dataserviceTimer = "";
                            }
                            if (m_sqlarr.length > 0) {
                                if (m_sqlarr[0].iseq == req.iseq) {
                                    m_sqlarr.shift();
                                }
                                if (m_sqlarr.length > 0) {
                                    //t.addlog('SoftphoneCore - executeupdate', 'to execute stacked request by success' + ', stack length = ' + m_sqlarr.length + ', first is  ' + m_sqlarr[0].iseq);
                                    logmsg("execupdate", "to execute stacked request by success", "stack length = " + m_sqlarr.length, "first is " + m_sqlarr[0].iseq);
                                    t.executeupdate(undefined, undefined, undefined, true);
                                }
                            }
                        }
                        if (data.code < 1) {
                            if (data.message) {
                                $F.alert(data.message);
                            }
                        }
                        result = 1;
                        if ($.isFunction(req.callback))
                            req.callback(data.message);
                    },
                    fail: function (xhr) {
                        duration = 0;
                        if (req.starttime) {
                            duration = new Date().valueOf() - req.starttime.valueOf();
                        }
                        //t.addlog('SoftphoneCore - executeupdate', 'execupdate(' + iseq + ').rows = -1, duration = ' + duration, xhr, 'executeupdatesql');
                        logmsg("executeupdate", "execupdate(" + iseq + ").rows = -1, duration = " + duration, xhr);
                        result = -1;
                        if (req.async) {
                            if (m_sqlarr.length > 0) {
                                /*
                                if (dataserviceTimer > 0) {
                                    clearTimeout(dataserviceTimer);
                                    dataserviceTimer = 0;
                                }
                                 */
                                if (m_sqlarr[0].iseq == req.iseq) {
                                    if (m_sqlarr[0].dataserviceTimer) {
                                        //clearTimeout(m_sqlarr[0].dataserviceTimer);
                                        $SC.stopTimer(m_sqlarr[0].dataserviceTimer);
                                    }
                                    m_sqlarr.shift();
                                }
                                if (m_sqlarr.length > 0) {
                                    //t.addlog('SoftphoneCore - executeupdate', 'to execute stacked request by fail'  + ', stack length = ' + m_sqlarr.length + ', first is  ' + m_sqlarr[0].iseq);
                                    logmsg("executeupdate", "to execute stacked request by fail", "stack length = " + m_sqlarr.length, "first is " + m_sqlarr[0].iseq);
                                    t.executeupdate(undefined, undefined, undefined, true);
                                }
                            }
                        }
                    }
                });
                return result;
            },

            /**
             * 执行一个存储过程
             */
            execprocedure: function (procedureObj) {
                var result, params = {};
                var proj = $E.getActiveProject();

                $F.dataService('DoProc', {
                    data: {
                        token: proj.token,
                        dbpool: procedureObj.dbpool || '',
                        name: procedureObj.name,
                        paras: procedureObj.params
                    },
                    digest: proj.digest,
                    async: (procedureObj.callback ? true : false),
                    success: function (data) {
                        if (procedureObj.callback) {
                            procedureObj.callback(data);
                        } else {
                            if (data.code > 0)
                                result = data.value;
                            else
                                $F.err('Cmds - doProcedure', data.message);
                        }
                    }
                });
                if (result !== undefined)
                    return result;
            },

            _getconfig: function (section, key, agentid, dn, options) {
                //getConfig : function(section, key, ctiType, rolegroupId, agentId, extension)
                //var ctitype = undefined;
                var rolegroupid = $E.staff.current.groupId;
                var ret = this.getConfig(section, key, ctitype, rolegroupid, agentid, dn);
                if (options && options.datatype) {
                    if (options.datatype == 'number') {
                        try {
                            ret = Number(ret);
                        } catch (e) {
                            ret = NaN;
                        }
                        if (isNaN(ret)) {
                            if (options.defaultvalue) {
                                ret = options.defaultvalue;
                            } else {
                                ret = 0;
                            }
                        }
                    }
                }
                return ret;
            },

            _getini: function (onload, agentid, dn) {
                m_logoutconfirmoncall = $SC._getconfig('COMMON', 'LogoutConfirm', agentid, dn);
                if (m_logoutconfirmoncall === undefined) {
                    m_logoutconfirmoncall = 1;
                }

                $SC.logconsole = $SC._getconfig('COMMON', 'LogConsole', agentid, dn);
                if ($SC.logconsole === undefined) {
                    $SC.logconsole = 1;
                }
                if (($SC.logconsole == 3 || $SC.logconsole == 4) && $E.softphone) {
                    $F.clientLogger.enabled = true;
                }
                $SC.logmaskedphoneno = $SC._getconfig('COMMON', 'LogMaskedPhoneNo', agentid, dn);
                if ($SC.logmaskedphoneno === undefined) {
                    $SC.logmaskedphoneno = 1;
                }

                m_timeout_login = $SC._getconfig("CTI", "timeoutlogin");
                if (m_timeout_login >= 2000 && m_timeout_login <= 30000) {
                } else {
                    m_timeout_login = 5000;
                }

                m_sqlkey_event_insert = $SC._getconfig("CTISave", "sqlkey_event_insert") || "softphone.event.insert.v202008";
                m_sqlkey_event_update = $SC._getconfig("CTISave", "sqlkey_event_update") || "softphone.event.update.v202008";
                m_sqlkey_event_updatecallstate = $SC._getconfig("CTISave", "sqlkey_event_updatecallstate") || "softphone.event.updatecallstate.v202008";
                m_sqlkey_event_setevent = $SC._getconfig("CTISave", "sqlkey_event_setevent") || "softphone.event.setevent.v202008";

                m_save_logagentdateil = $SC._getconfig('CTISave', 'LogAgentDetail') || 0;
                m_save_logagentlogininfo = $SC._getconfig('CTISave', 'LogAgentLoginInfo') || 0;
                //m_save_logcallinfo = $SC._getconfig('CTISave', 'LogCallInfo') || 1;
                m_save_agentcurrentstate = $SC._getconfig('CTISave', 'LogAgentCurrentState') || 0;
                m_save_stagenttoday = $SC._getconfig('CTISave', 'LogSTAAgentToday') || 0;
                m_save_agentcall = $SC._getconfig('CTISave', 'LogAgentCall') || 0;

                m_conf.m_ani = $SC._getconfig('CTI', 'ani', agentid, dn) || 'originalani';
                m_conf.m_dnis = $SC._getconfig('CTI', 'dnis', agentid, dn) || 'originaldnis';
                m_conf.traninternalani = $SC._getconfig('CTI', 'traninternalani', agentid, dn) || '';

                m_conf.m_report_always = $SC._getconfig('ReportAgent', 'ReportAlways', agentid, dn, {datatype: 'number'}) || 0;
                m_conf.m_report_dest = $SC._getconfig('ReportAgent', 'ReportDest', agentid, dn);
                m_conf.m_report_keytoreport = $SC._getconfig('ReportAgent', 'KeyToReport', agentid, dn) || 'WorkID';
                m_conf.m_report_userdatas = $SC._getconfig('ReportAgent', 'ReportUserDatas', agentid, dn) || 'AutoComplete=1|AgentID=[AgentID]';
                if (m_conf.m_report_userdatas) {
                    if (m_conf.m_report_userdatas.toLowerCase().indexOf('complete') < 0) {
                        m_conf.m_report_userdatas = 'AutoComplete=1|' + m_conf.m_report_userdatas;
                    }
                }
                m_conf.m_reportonsilentmonitored = $SC._getconfig('ReportAgent', 'ReportOnSilentMonitored', agentid, dn) || 0;
                m_conf.m_reportonrecorded = $SC._getconfig('ReportAgent', 'ReportOnRecorded', agentid, dn) || 0;

                m_conf.m_myd_dest = $SC._getconfig('CTI', 'manyidudest', agentid, dn);
                m_conf.m_myd_userdatas = $SC._getconfig('CTI', 'manyiduuserdatas', agentid, dn);

                //m_conf.reopen = $SC._getconfig('CTI', 'reopen', agentid, dn);

                m_conf.m_dnlist = $SC._getconfig('CTI', 'dnlist', agentid, dn);
                if (!m_conf.m_dnlist) {
                    m_conf.m_dnlist = '^[2-8][0-9]{1,4}$|^[^0-9]';
                }
                m_conf.m_autoprefix = $SC._getconfig('CTI', 'autoprefix', agentid, dn);
                if (!m_conf.m_autoprefix) {
                    m_conf.m_autoprefix = $SC._getconfig('CTI', 'AutoPrefix', agentid, dn);
                }
                this.autoPrefix = m_conf.m_autoprefix;
                //if (m_conf.m_autoprefix) {
                    /*
            		m_conf.m_dnlist = $SC._getconfig('CTI', 'dnlist', agentid, dn);
            		if (!m_conf.m_dnlist) {
            			m_conf.m_dnlist = '^[2-8][0-9]{1,4}$';
            		}
            		*/
                    m_conf.m_removeprefix = $SC._getconfig('CTI', 'removeprefix', agentid, dn);
                    //removeprefix: 1--same as autoprefix, 2--autoprefix and string of no leader char of autoprefix, 3--removeprefixlist
                    if (m_conf.m_removeprefix == 1) {
                        m_conf.m_removeprefixlist = [m_conf.m_autoprefix];
                    } else if (m_conf.m_removeprefix == 2) {
                        if (m_conf.m_autoprefix.length > 1) {
                            m_conf.m_removeprefixlist = [m_conf.m_autoprefix, m_conf.m_autoprefix.substr(1)];
                        } else {
                            m_conf.m_removeprefixlist = [m_conf.m_autoprefix];
                        }
                    } else if (m_conf.m_removeprefix == 3 || m_conf.m_removeprefix == 4) {
                        m_conf.m_removeprefixlist = $SC._getconfig('CTI', 'removeprefixlist', agentid, dn);
                        if (m_conf.m_removeprefixlist) {
                            if (typeof(m_conf.m_removeprefixlist) === "string") {
                                try {
                                    m_conf.m_removeprefixlist = eval(m_conf.m_removeprefixlist);
                                } catch (e) {
                                    if (m_conf.m_removeprefixlist.indexOf("|") > -1) {
                                        m_conf.m_removeprefixlist = m_conf.m_removeprefixlist.split('|');
                                    } else {
                                        m_conf.m_removeprefixlist = [m_conf.m_removeprefixlist];
                                    }
                                }
                            }

                            if (Array.isArray(m_conf.m_removeprefixlist)) {

                            } else {
                                m_conf.m_removeprefix = 4;
                                /*
                                if (m_conf.m_removeprefixlist.indexOf('[') > -1 && Array.isArray(eval(m_conf.m_removeprefixlist))) {
                                    m_conf.m_removeprefixlist = eval(m_conf.m_removeprefixlist);
                                } else {
                                    m_conf.m_removeprefixlist = m_conf.m_removeprefixlist.split('|');
                                }
                                 */
                            }
                        } else {
                            m_conf.m_removeprefix = [];
                        }
                    } else {
                        m_conf.m_removeprefix = 0;
                    }
                    if (m_conf.m_removeprefix) {
                        logmsg('SoftphoneCore -- config, removeprefix = ' + m_conf.m_removeprefix, m_conf.m_removeprefixlist);
                    }
                //} else {
                    //m_conf.m_dnlist = '';
                //}

                m_conf.m_DataUpdateAcceptedForDN = $SC._getconfig('CTI', 'DataUpdateAcceptedForDN', agentid, dn);
                m_conf.m_DNISAsANIOnPDS = $SC._getconfig('CTI', 'DNISAsANIOnPDS', agentid, dn);

                m_conf.m_areacode = $SC._getconfig('CTI', 'areacode', agentid, dn);

                m_conf.m_keepalive = $SC._getconfig('CTI', 'keepalive', agentid, dn);
                if (!m_conf.m_keepalive) {
                    m_conf.m_keepalive = 30000;
                } else {
                    m_conf.m_keepalive = parseInt(m_conf.m_keepalive);
                    if (m_conf.m_keepalive < 1000 && m_conf.m_keepalive > 0) {
                        m_conf.m_keepalive = m_conf.m_keepalive * 1000;
                    }
                }
                if (m_conf.m_keepalive > 180000) {
                    m_conf.m_keepalive = 180000;
                }

                //debugger;
                m_conf.m_autoWorkMode = $SC._getconfig('CTI', 'autoWorkMode', agentid, dn) || 2;
                m_conf.m_LogonStatus = $SC._getconfig("CTI", "LogonStatus", agentid, dn);
                if (m_conf.m_LogonStatus) {
                    m_conf.m_LogonStatus = m_conf.m_LogonStatus.toLowerCase();
                }
                m_conf.m_IBReleaseState = $SC._getconfig('CTI', 'IBReleaseState', agentid, dn) || "";
                m_conf.m_OBReleaseState = $SC._getconfig('CTI', 'OBReleaseState', agentid, dn) || "";
                m_conf.m_PreOBState = $SC._getconfig('CTI', 'PreOBState', agentid, dn);
                m_conf.m_PreOBReasonCode = $SC._getconfig('CTI', 'PreOBReasonCode', agentid, dn);
                m_conf.m_OBCallEndState = $SC._getconfig('CTI', 'OBCallEndState', agentid, dn) || "";
                m_conf.m_OBCallEndReasonCode = $SC._getconfig('CTI', 'OBCallEndReasonCode', agentid, dn);
                m_conf.m_IBCallEndState = $SC._getconfig('CTI', 'IBCallEndState', agentid, dn) || "";
                m_conf.m_IBCallEndReasonCode = $SC._getconfig('CTI', 'IBCallEndReasonCode', agentid, dn);
                m_conf.m_IBCallAbandonState = $SC._getconfig('CTI', 'IBCallAbandonState', agentid, dn) || "";
                m_conf.m_IBCallAbandonReasonCode = $SC._getconfig('CTI', 'IBCallAbandonReasonCode', agentid, dn);
                m_conf.m_OBCallAbandonState = $SC._getconfig('CTI', 'OBCallAbandonState', agentid, dn) || "";
                m_conf.m_OBCallAbandonReasonCode = $SC._getconfig('CTI', 'OBCallAbandonReasonCode', agentid, dn);

                m_conf.m_NoCallDisconnectIB = $SC._getconfig('CTI', 'NoCallDisconnectIB', agentid, dn) || 0;
                m_conf.m_NoCallDisconnectOB = $SC._getconfig('CTI', 'NoCallDisconnectOB', agentid, dn) || 0;

                m_conf.m_defaultreasoncode = $SC._getconfig('CTI', 'DefaultReasonCode', agentid, dn);
                m_conf.m_breakcode = $SC._getconfig("CTI", "BreakCode", agentid, dn);

                m_conf.m_AutoAnswer = $SC._getconfig('CTI', 'AutoAnswer', agentid, dn) || 0;
                m_conf.m_AutoAnswerDelay = $SC._getconfig('CTI', 'AutoAnswerDelay', agentid, dn) || 100;

                m_conf.m_MakeCallOnReady = $SC._getconfig('CTI', 'MakeCallOnReady', agentid, dn);
                if (m_conf.m_MakeCallOnReady == undefined) {
                    m_conf.m_MakeCallOnReady = 1;
                }
                m_conf.m_MakeCallOnNotReady = $SC._getconfig('CTI', 'MakeCallOnNotReady', agentid, dn);
                if (m_conf.m_MakeCallOnNotReady == undefined) {
                    m_conf.m_MakeCallOnNotReady = 1;
                }

                m_conf.m_canlogoutinwork = $SC._getconfig('CTI', 'canlogoutinwork', agentid, dn);
                if (m_conf.m_canlogoutinwork == undefined) {
                    m_conf.m_canlogoutinwork = 1;
                }

                m_conf.m_AutoWorkEndForInbound = $SC._getconfig('CTI', 'AutoWorkEndForInbound', agentid, dn) || 0;
                m_conf.m_AutoWorkEndForOutbound = $SC._getconfig('CTI', 'AutoWorkEndForOutbound', agentid, dn) || 0;
                if (m_conf.m_AutoWorkEndForInbound == 1) {
                    m_conf.m_AutoWorkEndDelayForInbound = $SC._getconfig('CTI', 'AutoWorkEndDelayForInbound', agentid, dn) || 100;
                    if (m_conf.m_AutoWorkEndDelayForInbound <= 0) {
                        m_conf.m_AutoWorkEndDelayForInbound = 100;
                    }
                }
                if (m_conf.m_AutoWorkEndDelayForOutbound == 1) {
                    m_conf.m_AutoWorkEndDelayForOutbound = $SC._getconfig('CTI', 'AutoWorkEndDelayForOutbound', agentid, dn) || 100;
                    if (m_conf.m_AutoWorkEndDelayForOutbound <= 0) {
                        m_conf.m_AutoWorkEndDelayForOutbound = 100;
                    }
                }

                //$SC.m_conf.m_AutoAnswer = m_conf.m_AutoAnswer;
                //$SC.m_conf.m_AutoAnswerdelay = m_conf.m_AutoAnswerDelay;
                if (m_conf.m_AutoAnswer == 1) {
                    //$SC.autoAnswer = true;
                }

                m_conf.m_transferondialinghold = $SC._getconfig('CTI', 'TransferOnDialingHold', agentid, dn);
                if (m_conf.m_transferondialinghold == undefined) {
                    m_conf.m_transferondialinghold = true;
                } else if (m_conf.m_transferondialinghold) {
                    m_conf.m_transferondialinghold = true;
                } else {
                    m_conf.m_transferondialinghold = false;
                }
                $SC.TransferOnDialingHold = m_conf.m_transferondialinghold;

                m_conf.m_transfer_defaultdata = $SC._getconfig('CTI', 'TransferDefaultData', agentid, dn);
                if (!m_conf.m_transfer_defaultdata) {
                    m_conf.m_transfer_defaultdata = 'E_Dest|Staff_ID';
                }

                m_conf.m_calloutdata = $SC._getconfig("CTI", "CallOutData", agentid, dn);
                if (m_conf.m_calloutdata && typeof(m_conf.m_calloutdata) === "string") {
                    m_conf.m_calloutdata = this.userdata2jsonuserdata(m_conf.m_calloutdata); //JSON.parse(m_conf.m_calloutdata);
                }

                //debugger;
                m_conf.m_AutoReleaseCall = $SC._getconfig('CTI', 'AutoReleaseCall', agentid, dn);
                if (m_conf.m_AutoReleaseCall == undefined || m_conf.m_AutoReleaseCall === '') {
                    m_conf.m_AutoReleaseCall = 1;
                }

                m_conf.m_ctidatkey = $SC._getconfig('CTISave', 'CTIDatKey', agentid, dn);
                if (!m_conf.m_ctidatkey) {
                    //m_conf.m_ctidatkey = 'UCID';
                    m_conf.m_ctidatkey = 'UCIDP';
                }
                m_conf.m_ctidatkey = m_conf.m_ctidatkey.toLowerCase();

                m_conf.m_defaultpassword = $SC._getconfig('CTI', 'DefaultPassword', agentid, dn) || '';
                m_conf.m_defaultpassword = m_conf.m_defaultpassword.toString();

                var ctiextras = $SC._getconfig('CTI', 'ctiextras', agentid, dn);
                m_ctiextras = {};
                if (ctiextras) {
                    logmsg('citextras: ' + ctiextras);
                    var reextra = false;
                    if (m_ctiextras) {
                        if (m_ctiextras.ctiextras == ctiextras) {
                            reextra = true;
                        }
                    }
                    if (!reextra) {
                        m_ctiextras = {};
                        m_ctiextras.ctiextras = ctiextras;
                        var extras;
                        if (Array.isArray(ctiextras)) {
                            extras = ctiextras;
                        } else {
                            if (ctiextras.indexOf('[') > -1) {
                                extras = eval(ctiextras);
                            }
                            if (Array.isArray(extras)) {

                            } else {
                                extras = ctiextras.split('|');
                            }
                        }
                        this.ctiextras = extras;
                        logmsg('SoftphoneCore -- to require ctiextras, total count = ' + extras.length);
                        for (let i = 0; i < extras.length; i++) {
                            try {
                                logmsg('SoftphoneCore -- require ctiextra ' + i + ': ' + extras[i]);
                                require([extras[i]], function (Extra) {
                                    m_ctiextras["extra" + i] = new Extra($E.getActiveProject(), {inittime: m_inittime});
                                });
                            } catch (err) {
                                logmsg('SoftphoneCore -- require ' + extras[i] + ' fail with err ' + JSON.stringify(err));
                            }
                        }
                        logmsg('SoftphoneCore -- to require ctiextras, done, total count = ' + extras.length);
                    }
                }

                var s = $SC._getconfig('CTI', 'statustimeout', agentid, dn);
                if (s) {
                    try {
                        if (typeof (s) == 'object') {
                            m_statustimeout = s;
                        } else {
                            m_statustimeout = JSON.parse(s);
                        }
                    } catch (e) {
                        logmsg('invalid statustimeout ' + s);
                    }
                }
            },

            /**
             * 获取系统参数值
             * @param paramName 系统参数名
             * @returns {string}
             */
            getParam: function (paramName) {
                return $E.getActiveProject().getParam(paramName);
            },

            /**
             * 查询数据库
             * @param sqlKey    配置在systemsql.properties中的key
             * @param params    相关参数数组
             * @param primaryKey    主键字段名
             * @returns {}
             *
             * 比如配置的sql为   ECore.staff.query = select staff_id,staffname,agent_id from staff where workstatus = @{C1}S
             * 这里调用时候就是  $SC.queryForMap('ECore.staff.query', ['ONLINE'], 'staff_id');
             * 返回的数据就是
             *  {
             *      SELITE : {
             *          STAFF_ID : 'SELITE',
             *          STAFFNAME : 'Elite',
             *          AGENT_ID : '5005'
             *      },
             *      A00001 : {
             *          ....
             *      },
             *      ...
             *  }
             */
            queryForMap: function (sqlKey, params, primaryKey) {
                return $E.getActiveProject().queryForMap(sqlKey, params, primaryKey);
            },


            /**
             * 构造event的bounddata对象
             * @param event 类似
             *      {
             *          event_guid : 'xxxxxx',
             *          calltype : 7,
             *          customer_guid : 'xxxxxx',
             *          ...
             *      }
             * @returns {BoundData}
             *
             */
            generateEventBoundData: function (event) {
                var eventBoundData = new BoundData("event" + $E.staff.epidSql);
                eventBoundData.KeyInfoEdit("event_guid");
                eventBoundData.setCreateInfo("CREATEDDATE", "CREATEDBY", $E.staff.id);
                eventBoundData.setModifyInfo("MODIFIEDDATE", "MODIFIEDBY", $E.staff.id);
                if (event) {
                    $.each(event, function (key, value) {
                        eventBoundData.setValue(key, value);
                    });
                }
                return eventBoundData;
            },

            /**
             * 保存boundData
             * @param boundData
             */
            saveBoundData: function (boundData) {
                var proj = $E.getActiveProject();
                var mRs = $F.ajaxSync("SystemDo5", {
                    token: proj.token,
                    dbPool: "",
                    xml: boundData.getData()
                }, proj.digest);
            },

            /**
             * 加载软电话ini
             */
            loadConfig: function (successFunc, errorFunc) {
                var sc = this;
                require([$E.softphoneBasePath + '/softphone/softphone.ini'], function (config) {
                //require([mypath + '/softphone.ini' + myfileext], function (config) {
                    sc.config = config;
                    if ($.isFunction(successFunc)) {
                        successFunc();
                    }
                }, function (err) {
                    if ($.isFunction(errorFunc)) {
                        errorFunc();
                    }
                });
            },


            /**
             * 获取ini信息
             先根据方式1（ctitype属性），得到了就ok；
             在根据方式2（工号相关属性），如果得到的不是缺省配值（缺省配置指：staffid、rolegroupid、agentid值都为空）时，得到了就ok；
             如果根据方式2没有得到，或者得到的是缺省配置值，再根据方式3（分机），得到了就ok；
             如果都没有，则根据ini配置，其中ini配置支持代码指定缺省值；
             * @param section
             * @param key
             * @param ctiType
             * @param rolegroupId
             * @param agentId
             * @param extension
             * @param options
             */
            getConfig: function (section, key, ctiType, rolegroupId, agentId, extension, options) {
                ctiType = ctiType || ctitype;

                var project = $E.getActiveProject(), configRet = {}, ret, resultArr;
                options = options || {ini: 1, db_ini: 1, db_ini_ext: 1, profile: 1};

                if (!$SC.staff) {
                    $SC.staff = {};
                    $SC.staff.agentId = $E.staff.agentId;
                    if (project && project.getStaffById) {
                        var staff = project.getStaffById($E.staff.id);
                        $SC.staff.extension = staff.bean ? staff.bean.EXTENSION : '';
                    }
                }

                //options.ini = (options.ini == 0)?0:1;
                //options.db_ini = (options.db_ini == 0)?0:1
                //options.db_ini_ext = (options.db_ini_ext == 0)?0:1
                //options.profile = (options.profile == 0)?0:1

                /**
                 * 获取方式1：如果有ctitype属性值，则根据数据库sql:softphone.db_ini_config_profile,C1值为ctitype属性值
                 有多条的话，需要在js中按如下优先级获取：agentid,rolegroupid 均为空，排前面的优先级高，即：
                 1）agentid相等，则ok
                 2）rolegroupid相等，则ok
                 3）此3个都为空
                 softphone.db_ini_config_profile=select record_guid,agent_id,inifile,sectionname,inikey,inivalue,rolegroup_id from db_ini_config{C1} where lower(profiletype)='ctitype' and lower(profilevalue)=lower(@{C2}S}) order by inifile,sectionname,inikey,agent_id,rolegroup_id
                 */
                if (ctiType && options.profile) {
                    //$F.log('softphone.core - getConfig', 'get ' + section + '.' + key + ' by ctiType: ' + ctiType);
                    if (!this.cache.config.ctiType[ctiType]) {
                        ret = project.commonQuerySync('softphone.db_ini_config_profile', [$E.staff.epidSql, ctiType]);
                        if (ret && ret.value[0].count > 0) {
                            logmsg('softphone.core.db_ini_config_profile, ctiType = ' + ctiType, ret.value[0].columns.toString(), ret.value[0].fields.toString());
                            resultArr = this.makejsonarray(ret, ['INIKEY', 'SECTIONNAME']); //	$F.makeJsonArray(ret.value[0]);
                            this.cache.config.ctiType[ctiType] = resultArr;
                            if (ret.value[0].columns.indexOf('ROLEGROUP_ID') >= 0) {
                                this.cache.config.ctityperolegroup = true;
                            }
                        } else {
                            this.cache.config.ctiType[ctiType] = "*";
                        }
                    }
                    if (this.cache.config.ctiType[ctiType] && this.cache.config.ctiType[ctiType] != "*") {
                        var query = '';
                        if (agentId) {
                            //configRet = jsonSql(this.cache.config.ctiType[ctiType], '* where SECTIONNAME=' + section+ ' && INIKEY=' + key.toLowerCase() + ' && (AGENT_ID =' + agentId + ' or AGENT_ID is null)', {trace:false});
                            query = "* where SECTIONNAME=" + section.toLowerCase() + " && INIKEY=" + key.toLowerCase() + " && (AGENT_ID =" + agentId + " || AGENT_ID = '')";
                            configRet = jsonSql(this.cache.config.ctiType[ctiType], query, {trace: false});
                            if (configRet && configRet.length > 0) {
                                return configRet[0].INIVALUE;
                            }
                        }
                        if (rolegroupId && this.cache.config.ctityperolegroup) {
                            //configRet = jsonSql(this.cache.config.ctiType[ctiType], '* where SECTIONNAME=' + section+ ' && INIKEY=' + key.toLowerCase() + ' && (ROLEGROUP_ID =' + rolegroupId + ' or ROLEGROUP_ID is null)', {trace:false});
                            query = "* where SECTIONNAME=" + section.toLowerCase() + " && INIKEY=" + key.toLowerCase() + " && (ROLEGROUP_ID =" + rolegroupId + " || ROLEGROUP_ID = '')";
                            configRet = jsonSql(this.cache.config.ctiType[ctiType], query, {trace: false});
                            if (configRet && configRet.length > 0) {
                                return configRet[0].INIVALUE;
                            }
                        }
                        //configRet = jsonSql(this.cache.config.ctiType[ctiType], '* where SECTIONNAME=' + section+ ' && INIKEY=' + key.toLowerCase() + ' && AGENT_ID is null && ROLEGROUP_ID is null', {trace:false});
                        if (this.cache.config.ctityperolegroup) {
                            query = "* where SECTIONNAME=" + section.toLowerCase() + " && INIKEY=" + key.toLowerCase() + " && AGENT_ID = '' && ROLEGROUP_ID =''"
                        } else {
                            query = "* where SECTIONNAME=" + section.toLowerCase() + " && INIKEY=" + key.toLowerCase() + " && AGENT_ID = ''"
                        }
                        configRet = jsonSql(this.cache.config.ctiType[ctiType], query, {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                    }
                    //return undefined;
                }

                /**
                 * 获取方式2：根据agentid、rolegroupid 属性值，数据库sql：softphone.db_ini_config，C1值为agentid，C2值为rolegroupid，
                 有多条的话，需要在js中按如下优先级获取：rolegroupid、agentid、均为空，排前面的优先级高
                 softphone.db_ini_config=select record_guid,agent_id,inifile,sectionname,inikey,inivalue,rolegroup_id from db_ini_config{C1} where (agent_id=@{C2}S or (agent_id is null or agent_id='')) and (rolegroup_id=@{C3}S or (rolegroup_id is null or rolegroup_id=''))) order by inifile,sectionname,inikey,agent_id,rolegroup_id
                 */
                if ((agentId || rolegroupId) && options.db_ini) {
                    //$F.log('softphone.core - getConfig', 'get ' + section + '.' + key + ' by agentId and rolegroupId: ' + agentId + ' - ' + rolegroupId);
                    if (!this.cache.config.agentRolegroup[agentId + '_' + rolegroupId]) {
                        ret = project.commonQuerySync('softphone.db_ini_config', [$E.staff.epidSql, agentId || '', rolegroupId || '']);
                        if (ret && ret.value[0].count > 0) {
                            resultArr = this.makejsonarray(ret, ['INIKEY', 'SECTIONNAME']); //	$F.makeJsonArray(ret.value[0]);
                            this.cache.config.agentRolegroup[agentId + '_' + rolegroupId] = resultArr;
                        } else {
                            this.cache.config.agentRolegroup[agentId + '_' + rolegroupId] = "*";
                        }
                    }
                    if (this.cache.config.agentRolegroup[agentId + '_' + rolegroupId] && this.cache.config.agentRolegroup[agentId + '_' + rolegroupId] != "*") {
                        configRet = jsonSql(this.cache.config.agentRolegroup[agentId + '_' + rolegroupId], '* where SECTIONNAME=' + section.toLowerCase() + ' && INIKEY=' + key.toLowerCase() + ' && ROLEGROUP_ID =' + rolegroupId + ' && AGENT_ID=' + agentId, {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                        configRet = jsonSql(this.cache.config.agentRolegroup[agentId + '_' + rolegroupId], '* where SECTIONNAME=' + section.toLowerCase() + ' && INIKEY=' + key.toLowerCase() + ' && AGENT_ID=' + agentId, {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                        configRet = jsonSql(this.cache.config.agentRolegroup[agentId + '_' + rolegroupId], '* where SECTIONNAME=' + section.toLowerCase() + ' && INIKEY=' + key.toLowerCase() + ' && ROLEGROUP_ID=' + rolegroupId, {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                        configRet = jsonSql(this.cache.config.agentRolegroup[agentId + '_' + rolegroupId], '* where SECTIONNAME=' + section.toLowerCase() + ' && INIKEY=' + key.toLowerCase(), {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                        //configRet = jsonSql(this.cache.config.agentRolegroup[agentId + '_' + rolegroupId], '* where SECTIONNAME=' + section+ ' && INIKEY=' + key.toLowerCase(), {trace:false});
                        //if(configRet && configRet.length > 0){
                        //    return configRet[0].INIVALUE;
                        //}
                    }
                }

                /**
                 * 获取方式3：根据extension属性值，数据库sql：softphone.db_ini_config_extension，C1值为extension
                 此情况不考虑多条
                 softphone.db_ini_config_extension.ORACLE=select record_guid,extensionstart,inifile,sectionname,inikey,inivalue from db_ini_config_extension{C1} where TO_NUMBER(@{C2}S)>=extensionstart and TO_NUMBER(@{C2}S)<=extensionend order by inifile,sectionname,inikey,extensionstart
                 softphone.db_ini_config_extension=select record_guid,extensionstart,inifile,sectionname,inikey,inivalue from db_ini_config_extension{C1} where cast(@{C2}S as int)>=extensionstart and cast(@{C2}S as int)<=extensionend order by inifile,sectionname,inikey,extensionstart
                 */
                if (extension && options.db_ini_ext) {
                    //$F.log('softphone.core - getConfig', 'get ' + section + '.' + key + ' by extension: ' + extension);
                    if (!this.cache.config.extension[extension]) {
                        var dbkey = 'softphone.db_ini_config_extension.v201610';
                        //if (project.getDbType() == 'ORACLE') {
                        //    dbkey = 'softphone.db_ini_config_extension.ORACLE';
                        //}
                        ret = project.commonQuerySync(dbkey, [$E.staff.epidSql, extension]);
                        if (ret && ret.value[0].count > 0) {
                            resultArr = this.makejsonarray(ret, ['INIKEY', 'SECTIONNAME']); //	$F.makeJsonArray(ret.value[0]);
                            this.cache.config.extension[extension] = resultArr;
                        } else {
                            this.cache.config.extension[extension] = "*";
                        }
                    }
                    if (this.cache.config.extension[extension] && this.cache.config.extension[extension] != "*") {
                        configRet = jsonSql(this.cache.config.extension[extension], '* where SECTIONNAME=' + section.toLowerCase() + ' && INIKEY=' + key.toLowerCase(), {trace: false});
                        if (configRet && configRet.length > 0) {
                            return configRet[0].INIVALUE;
                        }
                    }
                    //return undefined;
                }

                //获取方式4：根据ini
                if (this.config && options.ini) {
                    //$F.log('softphone.core - getConfig', 'get ' + section + '.' + key + ' from ini');
                    if (section && key) {
                        if (this.config[section]) {
                            return this.config[section][key.toLowerCase()];
                        } else if (this.config[section.toUpperCase()]) {
                            return this.config[section.toUpperCase()][key.toLowerCase()];
                        }
                    }
                }
                return undefined;
            },

            makejsonarray: function (ret, lowercasekeys) {
                for (let i = 0; i < ret.value[0].columns.length; i++) {
                    ret.value[0].columns[i] = ret.value[0].columns[i].toUpperCase();
                }

                if (lowercasekeys) {
                    if (!Array.isArray(lowercasekeys)) {
                        lowercasekeys = lowercasekeys.split("|");
                    }
                    for (let k = 0; k < lowercasekeys.length; k++) {
                        let lowercasekey = lowercasekeys[k];
                        var ikey = ret.value[0].columns.indexOf(lowercasekey);
                        if (ikey > -1) {
                            for (let i = 0; i < ret.value[0].count; i++) {
                                ret.value[0].fields[i][ikey] = ret.value[0].fields[i][ikey].toLowerCase();
                            }
                        }
                    }
                }
                return $F.makeJsonArray(ret.value[0]);
            },

            //str, decrypt == default false
            getdbenc: function (str, decrypt) {
                if (m_DBMASK == 1) {
                    return $F.Security.dbMasker(str, decrypt);
                } else {
                    return str;
                }
            },

            //str, decrypt == default false
            getdbmask: function (str, tablename, fieldname) {
                if (m_DBMASK == 1) {
                    var maskformat = this.getmaskformat(tablename, fieldname);
                    if (maskformat == '*') {
                        return str;
                    }
                    //tbd 20190708
                    return CtlUtils.expression(str, maskformat);
                } else {
                    return str;
                }
            },

            getmaskformat: function (tablename, columnname) {
                var ret = '';
                var inormal = 0;
                if (tablename.toLowerCase() == 'event') {
                    if (columnname.toLowerCase() == 'ani') {
                        inormal = 1;
                        if (m_masker_event_ani) {
                            return m_masker_event_ani;
                        }
                    } else if (columnname.toLowerCase() == 'dnis') {
                        inormal = 2;
                        if (m_masker_event_dnis) {
                            return m_masker_event_dnis;
                        }
                    }
                } else if (tablename.toLowerCase() == 'record') {
                    if (columnname.toLowerCase() == 'ani') {
                        inormal = 11;
                        if (m_masker_record_ani) {
                            return m_masker_record_ani;
                        }
                    } else if (columnname.toLowerCase() == 'dnis') {
                        inormal = 12;
                        if (m_masker_record_dnis) {
                            return m_masker_record_dnis;
                        }
                    }
                }
                if (m_masker) {
                    //var configRet = jsonSql(m_masker, '* where TABLE_NAME = ' + tablename + $E.staff.epidSql + ' && COLUMN_NAME = ' + columnname, {trace:false});
                    var configRet = jsonSql(m_masker, '* where TABLE_NAME =' + tablename + ' && COLUMN_NAME =' + columnname, {trace: false});
                    if (configRet && configRet.length > 0) {
                        ret = configRet[0].FORMAT;
                    }
                }
                if (!ret) {
                    ret = '*';
                }
                switch (inormal) {
                    case 1:
                        m_masker_event_ani = ret;
                        break;
                    case 2:
                        m_masker_event_dnis = ret;
                        break;
                    case 11:
                        m_masker_record_ani = ret;
                        break;
                    case 12:
                        m_masker_record_dnis = ret;
                        break;
                }
                return ret;
            },

            checkundefined: function (str) {
                if (!str || str == 'undefined') {
                    return '';
                } else {
                    return str;
                }
            },

            replacephonenum: function (str) {
                return str.replace(/(\d{3,})(\d{4})/g, '****$2');
                /*
        		var regx = /1[3456789]\d{9}/g;

        		var phoneNums = str.match(regx);
        		if (phoneNums) {
            		for(var i= 0;i<phoneNums.length;i++)
            		{
            			var temp = phoneNums[i];
            			temp = temp.replace(/(\d{3})\d{4}(\d{4})/, '$1****$2');
            			str = str.replace(phoneNums[i], temp);
            		}
        		}
        		return str;
            	 */
            },

            lang : function(key, defaultval) {
                if (softphonelang) {
                    var ret = getProperty(softphonelang, key);
                    if (ret) {
                        return ret;
                    }
                }
                return defaultval;
            },

            startTimer: function(interval, countlimit, startcount, timerName, callback) {
                if (m_timer) {
                    var timerUUID = Guid.raw();
                    m_timerCallers[timerUUID] = {};
                    m_timerCallers[timerUUID].timerUUID = timerUUID;
                    m_timerCallers[timerUUID].timerName = timerName;
                    m_timerCallers[timerUUID].callback = callback;
                    m_timerCallers[timerUUID].time = new Date().valueOf();
                    m_timer.postMessage({
                            "method":"startTimer"
                            , "params":{"timerName": timerName
                            ,"interval": interval
                            , "countlimit": countlimit
                            , "startcount": startcount
                            , "timerUUID": timerUUID
                        }
                    });
                    return timerUUID;
                } else {
                    logmsg("softphone.core.startTimer, no timer worker");
                }
            },

            stopTimer: function(timerUUID, timerId, timerName) {
                if (m_timer) {
                    if (timerUUID && m_timerCallers[timerUUID]) {
                        if (!timerId) {
                            timerId = m_timerCallers[timerUUID].timerId;
                        }
                        if (!timerName) {
                            timerName = m_timerCallers[timerUUID].timerName;
                        }
                    }
                    logmsg("softphone.core.stopTimer", timerUUID, timerId, timerName);
                    var timerId = m_timer.postMessage({"method":"stopTimer", "params":{"timerUUID": timerUUID, "timerId": timerId,"timerName": timerName}});
                }
            },

            addconsolelog: function (str) {
                m_logseq++;
                //logconsole: 1--Log to console, 2--Log to console when debug, 3--Log to console and to client, 4--Log to client
                if (!this.logconsole || this.logconsole == 1 || (this.logconsole == 2 && $E.debug) || this.logconsole == 3) {
                    var strlog = str;
                    if (this.logmaskedphoneno) {
                        strlog = this.replacephonenum(str);
                    }
                    console.log(strlog + "[softphonelog" + "-" + m_logseq + "]")
                }

                if (this.logconsole == 3 || this.logconsole == 4) {
                    $F.clientLogger.logToServer("[" + $E.staff.id + "-" + "softphonelog" + "-" + this.agentId + "-" + m_logseq + "]", str);
                }

            },

            log: function() {
                var msg = "[SoftphoneCore]";
                var i0 = 0;
                if (arguments[0] && typeof(arguments[0]) == "string" && arguments[0].substr(0,1)=="[") {
                    msg = arguments[0];
                    i0 = 1;
                }
                for (let i=i0; i<arguments.length; i++) {
                    var s1 = arguments[i];
                    if (s1 === null) {
                        s1 = "null";
                    } else if (typeof(s1) === "object") {
                        if (s1.callee) {
                            var args = s1;
                            var msg1 = "";
                            for (let j=0; j<args.length; j++) {
                                s1 = args[j];
                                if (typeof(s1) === "object") {
                                    s1 = JSON.stringify(s1);
                                }
                                if (j===0) {
                                    msg1 = s1;
                                } else {
                                    if ([" ", ",", ":"].indexOf(msg1.substr(msg1.length-1))>=0) {
                                        msg1 = msg1 + s1;
                                    } else {
                                        msg1 = msg1 + "," + s1;
                                    }
                                }
                            }
                            s1 = msg1;
                        } else {
                            s1 = JSON.stringify(s1);
                        }
                    } else if (typeof(s1) === "function") {
                        continue;
                    }
                    if (i===i0) {
                        msg = msg + s1;
                    } else {
                        if ([" ", ",", ":"].indexOf(msg.substr(msg.length-1))>=0) {
                            msg = msg + s1;
                        } else {
                            msg = msg + "," + s1;
                        }
                    }
                }
                try {
                    $SC.addconsolelog(msg);
                } catch (e) {
                    console.log(msg);
                }
            },

            loadJS: function(url, document, callback ){
                var script = document.createElement('script'),
                fn = callback || function(){};
                script.type = 'text/javascript';
                //IE
                if(script.readyState){
                    script.onreadystatechange = function(){
                        if( script.readyState == 'loaded' || script.readyState == 'complete' ){
                                script.onreadystatechange = null;
                            fn();
                        }
                    };
                }else{
                    //其他浏览器
                    script.onload = function(){
                        fn();
                    };
                }
                script.src = url;
                document.getElementsByTagName('head')[0].appendChild(script);
            },

            loadJSs: function(callfor, urls, document, callback) {
                $SC._loadJs(callfor, urls, document, 0, callback);
            },

            _loadJs: function(callfor, urls, document, i, callback) {
                $SC.addconsolelog("[" + callfor + "] js to load: " + urls[i]);
                this.loadJS(urls[i], document, function(){
                    $SC.addconsolelog("[" + callfor + "] js loaded: " + urls[i]);
                    if (i == urls.length-1) {
                        if ($.isFunction(callback)) {
                            callback();
                        }
                    } else {
                        $SC._loadJs(callfor, urls, document, i+1, callback);
                    }
                })
            },

            getngsbaseurl: function() {
                if (!this._ngsbaseurl) {
                    var s = window.document.URL;
                    var i= s.indexOf("/", 10);
                    i = s.indexOf("/", i+1);
                    this._ngsbaseurl = s.substr(0, i) + "/";
                }
                return this._ngsbaseurl;
            },

            parseserverurl: function(url) {
                try {
                    var a = url;
                    if (typeof(a) === "string") {
                        a = JSON.parse(url);
                    }
                    if (typeof(a) === "object") {

                    } else {
                        return this.parsewsurl(url);
                    }
                    var href = window.location.href;
                    var reg;
                    for (let v in a) {
                        reg = new RegExp(v);
                        if (reg.test(href)) {
                            return this.parsewsurl(a[v]);
                        }
                    }
                    if (a["default"]) {
                        return this.parsewsurl(a["default"]);
                    } else {
                        return this.parsewsurl(url);
                    }
                } catch (e) {
                    return this.parsewsurl(url);
                }
            },

            parsewsurl: function(url) {
                if (url) {
                    if (url.startWith("ws://") && window.document.URL.startWith("https://")) {
                        return url.replace("ws://", "wss://");
                    } else {
                        return url;
                    }
                } else {
                    return url;
                }
            }
        }

        window.$SC = new SoftphoneCore();
        return $SC;
    }());
}));